From b45deac4c0302278bace7f72e9c0f0ca92113913 Mon Sep 17 00:00:00 2001 From: overtorment Date: Sun, 15 Dec 2024 14:06:05 +0000 Subject: [PATCH 1/5] FIX: FCM pushes fixed due to deprecation of legacy api --- README.md | 6 +- package-lock.json | 411 ++++++++++++++++++++++++++- package.json | 3 +- src/class/GroundControlToMajorTom.ts | 188 +++++++----- src/controller/GroundController.ts | 5 +- src/index.ts | 2 +- src/worker-sender.ts | 12 +- 7 files changed, 547 insertions(+), 80 deletions(-) diff --git a/README.md b/README.md index 5c8ba93..d308b0c 100644 --- a/README.md +++ b/README.md @@ -87,18 +87,20 @@ Works well on Heroku (you'll need `JawsDB Maria` addon) Set them as env variables or put them into `.env` file in project root dir. - `JAWSDB_MARIA_URL` for example `mysql://username:password@host:port/database` -- `FCM_SERVER_KEY` hex encoded +- ~~`FCM_SERVER_KEY` hex encoded~~ deprecated (in favor of json key file) after FCM XMPP and HTTP legacy APIs was deprecated; the new one is HTTP v1 API; theres also a new uri to post payload - `APNS_P8` hex encoded - `APNS_P8_KID` issuer key which is "key ID" of your p8 file - `APPLE_TEAM_ID` "team ID" of your developer account - `BITCOIN_RPC` for example `http://username:password@host:8332` - `APNS_TOPIC` for example `io.bluewallet.bluewallet` +- `GOOGLE_KEY_FILE` - json file with Google key for FCM, in hex + ### Getting certificates - outdated https://dev.to/jakubkoci/react-native-push-notifications-313i - https://stackoverflow.com/questions/44631803/ios-swift-how-to-create-p8-file/67533665#67533665 -- get P8 hex `xxd -p file.p8 | tr -d '\n'` +- get P8 hex `xxd -p file.p8 | tr -d '\n'` (google key file as well) ### License diff --git a/package-lock.json b/package-lock.json index caf2163..c70f4dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "groundcontrol", - "version": "2.3.4", + "version": "3.0.0", "lockfileVersion": 2, "requires": true, "packages": { @@ -13,6 +13,7 @@ "dotenv": "^16.0.2", "express": "^4.21.1", "express-rate-limit": "^6.6.0", + "google-auth-library": "^9.15.0", "helmet": "^5.1.0", "jayson": "^3.6.6", "jsonwebtoken": "^9.0.0", @@ -173,6 +174,15 @@ "node": ">=0.4.0" } }, + "node_modules/agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -234,6 +244,15 @@ } ] }, + "node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", @@ -720,6 +739,12 @@ } ] }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "license": "MIT" + }, "node_modules/eyes": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", @@ -807,6 +832,68 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gaxios": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/gaxios/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/gaxios/node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/gcp-metadata": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", + "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^6.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/generate-function": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", @@ -871,6 +958,44 @@ "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", "dev": true }, + "node_modules/google-auth-library": { + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.0.tgz", + "integrity": "sha512-7ccSEJFDFO7exFbO6NRyC+xH8/mZ1GZGG2xxx9iHxZWcjUjJpjWxIMw3cofAKcueZ6DATiukmmprD7yavQHOyQ==", + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/google-auth-library/node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/google-auth-library/node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -882,6 +1007,40 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gtoken": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "license": "MIT", + "dependencies": { + "gaxios": "^6.0.0", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/gtoken/node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/gtoken/node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, "node_modules/has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", @@ -957,6 +1116,42 @@ "node": ">= 0.8" } }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -1022,6 +1217,18 @@ "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isomorphic-ws": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", @@ -1075,6 +1282,15 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -1770,6 +1986,12 @@ "node": ">=0.6" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, "node_modules/ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", @@ -2133,6 +2355,22 @@ "node": ">= 8" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", @@ -2375,6 +2613,11 @@ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==" }, + "agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==" + }, "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -2416,6 +2659,11 @@ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" }, + "bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==" + }, "body-parser": { "version": "1.20.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", @@ -2759,6 +3007,11 @@ "integrity": "sha512-HFN2+4ZGdkQOS8Qli4z6knmJFnw6lZed67o6b7RGplWeb1Z0s8VXaj3dUgPIdm9hrhZXTRpCTHXA0/2Eqex0vA==", "requires": {} }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, "eyes": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", @@ -2815,6 +3068,42 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" }, + "gaxios": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", + "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", + "requires": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "is-stream": "^2.0.0", + "node-fetch": "^2.6.9", + "uuid": "^9.0.1" + }, + "dependencies": { + "node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==" + } + } + }, + "gcp-metadata": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.0.tgz", + "integrity": "sha512-Jh/AIwwgaxan+7ZUUmRLCjtchyDiqh4KjBJ5tW3plBZb5iL/BPcso8A5DlzeD9qlw0duCamnNdpFjxwaT0KyKg==", + "requires": { + "gaxios": "^6.0.0", + "json-bigint": "^1.0.0" + } + }, "generate-function": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", @@ -2864,6 +3153,40 @@ "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", "dev": true }, + "google-auth-library": { + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.0.tgz", + "integrity": "sha512-7ccSEJFDFO7exFbO6NRyC+xH8/mZ1GZGG2xxx9iHxZWcjUjJpjWxIMw3cofAKcueZ6DATiukmmprD7yavQHOyQ==", + "requires": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^6.1.1", + "gcp-metadata": "^6.1.0", + "gtoken": "^7.0.0", + "jws": "^4.0.0" + }, + "dependencies": { + "jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + } + } + }, "gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -2872,6 +3195,36 @@ "get-intrinsic": "^1.1.3" } }, + "gtoken": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", + "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", + "requires": { + "gaxios": "^6.0.0", + "jws": "^4.0.0" + }, + "dependencies": { + "jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "requires": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + } + } + }, "has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", @@ -2920,6 +3273,30 @@ "toidentifier": "1.0.1" } }, + "https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "requires": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "requires": { + "ms": "^2.1.3" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -2962,6 +3339,11 @@ "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=" }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, "isomorphic-ws": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", @@ -3006,6 +3388,14 @@ "argparse": "^2.0.1" } }, + "json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "requires": { + "bignumber.js": "^9.0.0" + } + }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -3518,6 +3908,11 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "ts-node": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", @@ -3709,6 +4104,20 @@ "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==" }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/package.json b/package.json index cebc641..24eec2d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "groundcontrol", - "version": "2.3.4", + "version": "3.0.0", "description": "GroundControl push server API", "devDependencies": { "@types/node": "18.7.16", @@ -13,6 +13,7 @@ "dotenv": "^16.0.2", "express": "^4.21.1", "express-rate-limit": "^6.6.0", + "google-auth-library": "^9.15.0", "helmet": "^5.1.0", "jayson": "^3.6.6", "jsonwebtoken": "^9.0.0", diff --git a/src/class/GroundControlToMajorTom.ts b/src/class/GroundControlToMajorTom.ts index 9b91025..0f4cfe6 100644 --- a/src/class/GroundControlToMajorTom.ts +++ b/src/class/GroundControlToMajorTom.ts @@ -1,18 +1,26 @@ -import { DataSource } from "typeorm"; -import { PushLog } from "../entity/PushLog"; -import { TokenToAddress } from "../entity/TokenToAddress"; -import { TokenToHash } from "../entity/TokenToHash"; -import { TokenToTxid } from "../entity/TokenToTxid"; -import { components } from "../openapi/api"; +import {GoogleAuth} from "google-auth-library"; +import {DataSource} from "typeorm"; +import {PushLog} from "../entity/PushLog"; +import {TokenToAddress} from "../entity/TokenToAddress"; +import {TokenToHash} from "../entity/TokenToHash"; +import {TokenToTxid} from "../entity/TokenToTxid"; +import {components} from "../openapi/api"; const jwt = require("jsonwebtoken"); const http2 = require("http2"); require("dotenv").config(); -if (!process.env.APNS_P8 || !process.env.APPLE_TEAM_ID || !process.env.APNS_P8_KID || !process.env.FCM_SERVER_KEY) { +if (!process.env.APNS_P8 || !process.env.APPLE_TEAM_ID || !process.env.APNS_P8_KID || !process.env.GOOGLE_KEY_FILE) { console.error("not all env variables set"); process.exit(); } +const keyFileStr = Buffer.from(process.env.GOOGLE_KEY_FILE, "hex").toString("ascii"); +require('fs').writeFileSync('/tmp/google_key_file.json', keyFileStr, {encoding: "ascii"}); +const auth = new GoogleAuth({ + keyFile: '/tmp/google_key_file.json', + scopes: 'https://www.googleapis.com/auth/cloud-platform', +}); + /** * Since we cant attach any code to openapi schema definition, this is a repository of transforming pushnotification object * (thats created from apenapi schema) to actual payload thats gona be pushed to fcm/apns. In most basic case we would @@ -29,8 +37,10 @@ export class GroundControlToMajorTom { protected static _jwtToken: string = ""; protected static _jwtTokenMicroTimestamp: number = 0; - static getGoogleServerKey() { - return process.env.FCM_SERVER_KEY; + static async getGoogleCredentials() { + const client = await auth.getClient(); + const accessTokenResponse = await client.getAccessToken(); + return accessTokenResponse.token; // `accessTokenResponse.token` contains the short-lived access token } static getApnsJwtToken(): string { @@ -64,15 +74,19 @@ export class GroundControlToMajorTom { serverKey: string, apnsP8: string, pushNotification: components["schemas"]["PushNotificationOnchainAddressGotUnconfirmedTransaction"] - ): Promise<[object, object]> { + ): Promise { const fcmPayload = { - data: {}, - notification: { - title: "New unconfirmed transaction", - body: "You received new transfer on " + GroundControlToMajorTom.shortenAddress(pushNotification.address), - badge: pushNotification.badge, - tag: pushNotification.txid, - }, + message: { + token: '', + data: { + badge: String(pushNotification.badge), + tag: pushNotification.txid, + }, + notification: { + title: "New unconfirmed transaction", + body: "You received new transfer on " + GroundControlToMajorTom.shortenAddress(pushNotification.address), + }, + } }; const apnsPayload = { @@ -91,14 +105,17 @@ export class GroundControlToMajorTom { if (pushNotification.os === "ios") return GroundControlToMajorTom._pushToApns(dataSource, apnsP8, pushNotification.token, apnsPayload, pushNotification, pushNotification.txid); } - static async pushOnchainTxidGotConfirmed(dataSource: DataSource, serverKey: string, apnsP8: string, pushNotification: components["schemas"]["PushNotificationTxidGotConfirmed"]): Promise<[object, object]> { + static async pushOnchainTxidGotConfirmed(dataSource: DataSource, serverKey: string, apnsP8: string, pushNotification: components["schemas"]["PushNotificationTxidGotConfirmed"]): Promise { const fcmPayload = { - data: {}, - notification: { - title: "Transaction - Confirmed", - body: "Your transaction " + GroundControlToMajorTom.shortenTxid(pushNotification.txid) + " has been confirmed", - badge: pushNotification.badge, - tag: pushNotification.txid, + message: { + data: { + badge: String(pushNotification.badge), + tag: pushNotification.txid, + }, + notification: { + title: "Transaction - Confirmed", + body: "Your transaction " + GroundControlToMajorTom.shortenTxid(pushNotification.txid) + " has been confirmed", + }, }, }; @@ -118,12 +135,14 @@ export class GroundControlToMajorTom { if (pushNotification.os === "ios") return GroundControlToMajorTom._pushToApns(dataSource, apnsP8, pushNotification.token, apnsPayload, pushNotification, pushNotification.txid); } - static async pushMessage(dataSource: DataSource, serverKey: string, apnsP8: string, pushNotification: components["schemas"]["PushNotificationMessage"]): Promise<[object, object]> { + static async pushMessage(dataSource: DataSource, serverKey: string, apnsP8: string, pushNotification: components["schemas"]["PushNotificationMessage"]): Promise { const fcmPayload = { - data: {}, - notification: { - title: "Message", - body: pushNotification.text, + message: { + data: {}, + notification: { + title: "Message", + body: pushNotification.text, + }, }, }; @@ -143,15 +162,19 @@ export class GroundControlToMajorTom { if (pushNotification.os === "ios") return GroundControlToMajorTom._pushToApns(dataSource, apnsP8, pushNotification.token, apnsPayload, pushNotification, pushNotification.txid); } - static async pushOnchainAddressWasPaid(dataSource: DataSource, serverKey: string, apnsP8: string, pushNotification: components["schemas"]["PushNotificationOnchainAddressGotPaid"]): Promise<[object, object]> { + static async pushOnchainAddressWasPaid(dataSource: DataSource, serverKey: string, apnsP8: string, pushNotification: components["schemas"]["PushNotificationOnchainAddressGotPaid"]): Promise { const fcmPayload = { - data: {}, - notification: { - title: "+" + pushNotification.sat + " sats", - body: "Received on " + GroundControlToMajorTom.shortenAddress(pushNotification.address), - badge: pushNotification.badge, - tag: pushNotification.txid, - }, + message: { + token: '', + data: { + badge: String(pushNotification.badge), + tag: pushNotification.txid, + }, + notification: { + title: "+" + pushNotification.sat + " sats", + body: "Received on " + GroundControlToMajorTom.shortenAddress(pushNotification.address), + }, + } }; const apnsPayload = { @@ -170,14 +193,17 @@ export class GroundControlToMajorTom { if (pushNotification.os === "ios") return GroundControlToMajorTom._pushToApns(dataSource, apnsP8, pushNotification.token, apnsPayload, pushNotification, pushNotification.txid); } - static async pushLightningInvoicePaid(dataSource: DataSource, serverKey: string, apnsP8: string, pushNotification: components["schemas"]["PushNotificationLightningInvoicePaid"]): Promise<[object, object]> { + static async pushLightningInvoicePaid(dataSource: DataSource, serverKey: string, apnsP8: string, pushNotification: components["schemas"]["PushNotificationLightningInvoicePaid"]): Promise { const fcmPayload = { - data: {}, - notification: { - body: "Paid: " + (pushNotification.memo || "your invoice"), - title: "+" + pushNotification.sat + " sats", - badge: pushNotification.badge, - tag: pushNotification.hash, + message: { + data: { + badge: String(pushNotification.badge), + tag: pushNotification.hash, + }, + notification: { + body: "Paid: " + (pushNotification.memo || "your invoice"), + title: "+" + pushNotification.sat + " sats", + }, }, }; @@ -197,7 +223,7 @@ export class GroundControlToMajorTom { if (pushNotification.os === "ios") return GroundControlToMajorTom._pushToApns(dataSource, apnsP8, pushNotification.token, apnsPayload, pushNotification, pushNotification.hash); } - protected static async _pushToApns(dataSource: DataSource, apnsP8: string, token: string, apnsPayload: object, pushNotification: components["schemas"]["PushNotificationBase"], collapseId): Promise<[object, object]> { + protected static async _pushToApns(dataSource: DataSource, apnsP8: string, token: string, apnsPayload: object, pushNotification: components["schemas"]["PushNotificationBase"], collapseId): Promise { return new Promise(function (resolve) { // we pass some of the notification properties as data properties to FCM payload: for (let dataKey of Object.keys(pushNotification)) { @@ -239,7 +265,7 @@ export class GroundControlToMajorTom { success: responseJson[":status"] === 200, }); - resolve([apnsPayload, responseJson]); + resolve(); }); request.setEncoding("utf8"); @@ -267,48 +293,50 @@ export class GroundControlToMajorTom { success: responseJson[":status"] === 200, }); - resolve([apnsPayload, responseJson]); + resolve(); }); request.end(); }); } - protected static async _pushToFcm(dataSource: DataSource, serverKey: string, token: string, fcmPayload: object, pushNotification: components["schemas"]["PushNotificationBase"]): Promise<[object, object]> { - fcmPayload["to"] = token; - fcmPayload["priority"] = "high"; + protected static async _pushToFcm(dataSource: DataSource, bearer: string, token: string, fcmPayload: object, pushNotification: components["schemas"]["PushNotificationBase"]): Promise { + fcmPayload["message"]["token"] = token; // now, we pass some of the notification properties as data properties to FCM payload: for (let dataKey of Object.keys(pushNotification)) { if (["token", "os", "badge"].includes(dataKey)) continue; - fcmPayload["data"][dataKey] = pushNotification[dataKey]; + fcmPayload["message"]["data"][dataKey] = String(pushNotification[dataKey]); } // @ts-ignore - const rawResponse = await fetch("https://fcm.googleapis.com/fcm/send", { + const rawResponse = await fetch("https://fcm.googleapis.com/v1/projects/bluewallet-d7cd5/messages:send", { method: "POST", headers: { - Authorization: "key=" + serverKey, + Authorization: `Bearer ${bearer}`, "Content-Type": "application/json", - Host: "fcm.googleapis.com", }, body: JSON.stringify(Object.assign({}, fcmPayload)), }); - const responseJson = await rawResponse.json(); - delete fcmPayload["to"]; // compacting a bit, we dont need token in payload as well + let responseText: string; + try { + responseText = await rawResponse.text(); + } catch (error) { + console.error("error getting response from FCM", error); + } + + delete fcmPayload["message"]["token"]; // compacting a bit, we dont need token in payload as well - GroundControlToMajorTom.processFcmResponse(dataSource, responseJson, token); + const success = GroundControlToMajorTom.processFcmResponse(dataSource, responseText, token); const PushLogRepository = dataSource.getRepository(PushLog); await PushLogRepository.save({ token: token, os: "android", payload: JSON.stringify(fcmPayload), - response: JSON.stringify(responseJson), - success: !!responseJson["success"], + response: responseText, + success, }); - - return [fcmPayload, responseJson]; } static async killDeadToken(dataSource: DataSource, token: string) { @@ -318,21 +346,45 @@ export class GroundControlToMajorTom { await dataSource.getRepository(TokenToHash).createQueryBuilder().delete().where("token = :token", { token }).execute(); } - static processFcmResponse(dataSource: DataSource, response, token: string) { - if (response && response.results && Array.isArray(response.results) && response.results.length === 1) { - if (response.results[0] && response.results[0].error && ["NotRegistered"].includes(response.results[0].error)) { - return GroundControlToMajorTom.killDeadToken(dataSource, token); + static processFcmResponse(dataSource: DataSource, responseText: string, token: string): boolean { + try { + const response = JSON.parse(responseText); + + if (response?.error) { + if (response.error.code === 404) { + GroundControlToMajorTom.killDeadToken(dataSource, token); + return false; + } + + // additonal check for the same thing, just for any case + if (Array.isArray(response?.error?.details)) { + for (const detail of response.error.details) { + if (detail.errorCode === "UNREGISTERED") { + GroundControlToMajorTom.killDeadToken(dataSource, token); + return false; + } + } + } } - } else if (response && response.results && Array.isArray(response.results) && response.results.length !== 1) { - console.error("Expected only single result in FCM response, cant handle batch responses yet (zero response also means smth is wrong):", response); + + if (response?.name) { + // thats a sign that payload is accepted and might be delivered + return true; + } + } catch (_) { + console.error("error parsing FCM response", responseText); + return false; } + + return false; } static processApnsResponse(dataSource: DataSource, response, token: string) { if (response && response.data) { try { + console.log('parsing', response.data); const data = JSON.parse(response.data); - if (data && data.reason && ["Unregistered", "BadDeviceToken"].includes(data.reason)) return GroundControlToMajorTom.killDeadToken(dataSource, token); + if (data && data.reason && ["Unregistered", "BadDeviceToken", "DeviceTokenNotForTopic"].includes(data.reason)) return GroundControlToMajorTom.killDeadToken(dataSource, token); } catch (_) {} } } diff --git a/src/controller/GroundController.ts b/src/controller/GroundController.ts index 4494cb0..52acaf9 100644 --- a/src/controller/GroundController.ts +++ b/src/controller/GroundController.ts @@ -11,7 +11,7 @@ import dataSource from "../data-source"; import { paths, components } from "../openapi/api"; require("dotenv").config(); const pck = require("../../package.json"); -if (!process.env.JAWSDB_MARIA_URL || !process.env.FCM_SERVER_KEY || !process.env.APNS_P8 || !process.env.APNS_TOPIC || !process.env.APPLE_TEAM_ID || !process.env.APNS_P8_KID) { +if (!process.env.JAWSDB_MARIA_URL || !process.env.GOOGLE_KEY_FILE || !process.env.APNS_P8 || !process.env.APNS_TOPIC || !process.env.APPLE_TEAM_ID || !process.env.APNS_P8_KID) { console.error("not all env variables set"); process.exit(); } @@ -19,6 +19,9 @@ if (!process.env.JAWSDB_MARIA_URL || !process.env.FCM_SERVER_KEY || !process.env const LAST_PROCESSED_BLOCK = "LAST_PROCESSED_BLOCK"; const ADDRESS_IGNORE_LIST = [ + "1NXNHZr6Pbzi3VStcgaxwEhspTWNXQ3Q4G", + "bc1qee7hk4a3k3km7j8hwclm0pkl76dhhgxay5nevu", + "bc1qclyfsxuu8vcwq38yygs5zrskwacq8sjlyvk9mx", "bc1qltxjty7xfrnkzlrhmxpcekknr3uncne8sht7rn", "bc1qwqdg6squsna38e46795at95yu9atm8azzmyvckulcc7kytlcckxswvvzej", "bc1qw8wrek2m7nlqldll66ajnwr9mh64syvkt67zlu", diff --git a/src/index.ts b/src/index.ts index 742c4e5..d931808 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,7 +7,7 @@ import dataSource from "./data-source"; require("dotenv").config(); const helmet = require("helmet"); const cors = require("cors"); -if (!process.env.JAWSDB_MARIA_URL || !process.env.FCM_SERVER_KEY || !process.env.APNS_P8 || !process.env.APNS_TOPIC) { +if (!process.env.JAWSDB_MARIA_URL || !process.env.GOOGLE_KEY_FILE || !process.env.APNS_P8 || !process.env.APNS_TOPIC) { console.error("not all env variables set"); process.exit(); } diff --git a/src/worker-sender.ts b/src/worker-sender.ts index 20573f4..98a926b 100644 --- a/src/worker-sender.ts +++ b/src/worker-sender.ts @@ -6,7 +6,7 @@ import { NOTIFICATION_LEVEL_NEWS, NOTIFICATION_LEVEL_PRICE, NOTIFICATION_LEVEL_T import dataSource from "./data-source"; import { components } from "./openapi/api"; require("dotenv").config(); -if (!process.env.FCM_SERVER_KEY || !process.env.APNS_P8 || !process.env.APNS_TOPIC || !process.env.APPLE_TEAM_ID || !process.env.APNS_P8_KID) { +if (!process.env.GOOGLE_KEY_FILE || !process.env.APNS_P8 || !process.env.APNS_TOPIC || !process.env.APPLE_TEAM_ID || !process.env.APNS_P8_KID) { console.error("not all env variables set"); process.exit(); } @@ -107,31 +107,31 @@ dataSource case 2: payload = payload; process.env.VERBOSE && console.log("pushing to token", payload.token, payload.os); - await GroundControlToMajorTom.pushOnchainAddressWasPaid(connection, GroundControlToMajorTom.getGoogleServerKey(), GroundControlToMajorTom.getApnsJwtToken(), payload); + await GroundControlToMajorTom.pushOnchainAddressWasPaid(connection, await GroundControlToMajorTom.getGoogleCredentials(), GroundControlToMajorTom.getApnsJwtToken(), payload); await sendQueueRepository.remove(record); break; case 3: payload = payload; process.env.VERBOSE && console.log("pushing to token", payload.token, payload.os); - await GroundControlToMajorTom.pushOnchainAddressGotUnconfirmedTransaction(connection, GroundControlToMajorTom.getGoogleServerKey(), GroundControlToMajorTom.getApnsJwtToken(), payload); + await GroundControlToMajorTom.pushOnchainAddressGotUnconfirmedTransaction(connection, await GroundControlToMajorTom.getGoogleCredentials(), GroundControlToMajorTom.getApnsJwtToken(), payload); await sendQueueRepository.remove(record); break; case 1: payload = payload; process.env.VERBOSE && console.log("pushing to token", payload.token, payload.os); - await GroundControlToMajorTom.pushLightningInvoicePaid(connection, GroundControlToMajorTom.getGoogleServerKey(), GroundControlToMajorTom.getApnsJwtToken(), payload); + await GroundControlToMajorTom.pushLightningInvoicePaid(connection, await GroundControlToMajorTom.getGoogleCredentials(), GroundControlToMajorTom.getApnsJwtToken(), payload); await sendQueueRepository.remove(record); break; case 4: payload = payload; process.env.VERBOSE && console.log("pushing to token", payload.token, payload.os); - await GroundControlToMajorTom.pushOnchainTxidGotConfirmed(connection, GroundControlToMajorTom.getGoogleServerKey(), GroundControlToMajorTom.getApnsJwtToken(), payload); + await GroundControlToMajorTom.pushOnchainTxidGotConfirmed(connection, await GroundControlToMajorTom.getGoogleCredentials(), GroundControlToMajorTom.getApnsJwtToken(), payload); await sendQueueRepository.remove(record); break; case 5: payload = payload; process.env.VERBOSE && console.log("pushing to token", payload.token, payload.os); - await GroundControlToMajorTom.pushMessage(connection, GroundControlToMajorTom.getGoogleServerKey(), GroundControlToMajorTom.getApnsJwtToken(), payload); + await GroundControlToMajorTom.pushMessage(connection, await GroundControlToMajorTom.getGoogleCredentials(), GroundControlToMajorTom.getApnsJwtToken(), payload); await sendQueueRepository.remove(record); break; default: From 8cd02ff64ceaa1190107430aa5d78b17d154e64a Mon Sep 17 00:00:00 2001 From: overtorment Date: Sun, 15 Dec 2024 14:15:56 +0000 Subject: [PATCH 2/5] FIX: FCM pushes fixed due to deprecation of legacy api --- README.md | 2 ++ src/class/GroundControlToMajorTom.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d308b0c..9a033dd 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ Set them as env variables or put them into `.env` file in project root dir. - `BITCOIN_RPC` for example `http://username:password@host:8332` - `APNS_TOPIC` for example `io.bluewallet.bluewallet` - `GOOGLE_KEY_FILE` - json file with Google key for FCM, in hex +- `GOOGLE_PROJECT_ID` - acquired with the key file ### Getting certificates @@ -101,6 +102,7 @@ Set them as env variables or put them into `.env` file in project root dir. - outdated https://dev.to/jakubkoci/react-native-push-notifications-313i - https://stackoverflow.com/questions/44631803/ios-swift-how-to-create-p8-file/67533665#67533665 - get P8 hex `xxd -p file.p8 | tr -d '\n'` (google key file as well) +- https://firebase.google.com/docs/cloud-messaging/migrate-v1 ### License diff --git a/src/class/GroundControlToMajorTom.ts b/src/class/GroundControlToMajorTom.ts index 0f4cfe6..9556b77 100644 --- a/src/class/GroundControlToMajorTom.ts +++ b/src/class/GroundControlToMajorTom.ts @@ -309,7 +309,7 @@ export class GroundControlToMajorTom { } // @ts-ignore - const rawResponse = await fetch("https://fcm.googleapis.com/v1/projects/bluewallet-d7cd5/messages:send", { + const rawResponse = await fetch(`https://fcm.googleapis.com/v1/projects/${process.env.GOOGLE_PROJECT_ID}/messages:send`, { method: "POST", headers: { Authorization: `Bearer ${bearer}`, From 5e5ae184f6198f979f1f666e98e0372b0744d811 Mon Sep 17 00:00:00 2001 From: overtorment Date: Sun, 15 Dec 2024 14:21:57 +0000 Subject: [PATCH 3/5] FIX: FCM pushes fixed due to deprecation of legacy api --- src/class/GroundControlToMajorTom.ts | 2 +- src/controller/GroundController.ts | 2 +- src/index.ts | 2 +- src/worker-sender.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/class/GroundControlToMajorTom.ts b/src/class/GroundControlToMajorTom.ts index 9556b77..95ea01c 100644 --- a/src/class/GroundControlToMajorTom.ts +++ b/src/class/GroundControlToMajorTom.ts @@ -9,7 +9,7 @@ const jwt = require("jsonwebtoken"); const http2 = require("http2"); require("dotenv").config(); -if (!process.env.APNS_P8 || !process.env.APPLE_TEAM_ID || !process.env.APNS_P8_KID || !process.env.GOOGLE_KEY_FILE) { +if (!process.env.APNS_P8 || !process.env.APPLE_TEAM_ID || !process.env.APNS_P8_KID || !process.env.GOOGLE_KEY_FILE || !process.env.GOOGLE_PROJECT_ID) { console.error("not all env variables set"); process.exit(); } diff --git a/src/controller/GroundController.ts b/src/controller/GroundController.ts index 52acaf9..8fb96c9 100644 --- a/src/controller/GroundController.ts +++ b/src/controller/GroundController.ts @@ -11,7 +11,7 @@ import dataSource from "../data-source"; import { paths, components } from "../openapi/api"; require("dotenv").config(); const pck = require("../../package.json"); -if (!process.env.JAWSDB_MARIA_URL || !process.env.GOOGLE_KEY_FILE || !process.env.APNS_P8 || !process.env.APNS_TOPIC || !process.env.APPLE_TEAM_ID || !process.env.APNS_P8_KID) { +if (!process.env.JAWSDB_MARIA_URL || !process.env.GOOGLE_KEY_FILE || !process.env.APNS_P8 || !process.env.APNS_TOPIC || !process.env.APPLE_TEAM_ID || !process.env.APNS_P8_KID || !process.env.GOOGLE_PROJECT_ID) { console.error("not all env variables set"); process.exit(); } diff --git a/src/index.ts b/src/index.ts index d931808..577dd79 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,7 +7,7 @@ import dataSource from "./data-source"; require("dotenv").config(); const helmet = require("helmet"); const cors = require("cors"); -if (!process.env.JAWSDB_MARIA_URL || !process.env.GOOGLE_KEY_FILE || !process.env.APNS_P8 || !process.env.APNS_TOPIC) { +if (!process.env.JAWSDB_MARIA_URL || !process.env.GOOGLE_KEY_FILE || !process.env.APNS_P8 || !process.env.APNS_TOPIC || !process.env.GOOGLE_PROJECT_ID) { console.error("not all env variables set"); process.exit(); } diff --git a/src/worker-sender.ts b/src/worker-sender.ts index 98a926b..d6efacc 100644 --- a/src/worker-sender.ts +++ b/src/worker-sender.ts @@ -6,7 +6,7 @@ import { NOTIFICATION_LEVEL_NEWS, NOTIFICATION_LEVEL_PRICE, NOTIFICATION_LEVEL_T import dataSource from "./data-source"; import { components } from "./openapi/api"; require("dotenv").config(); -if (!process.env.GOOGLE_KEY_FILE || !process.env.APNS_P8 || !process.env.APNS_TOPIC || !process.env.APPLE_TEAM_ID || !process.env.APNS_P8_KID) { +if (!process.env.GOOGLE_KEY_FILE || !process.env.APNS_P8 || !process.env.APNS_TOPIC || !process.env.APPLE_TEAM_ID || !process.env.APNS_P8_KID || !process.env.GOOGLE_PROJECT_ID) { console.error("not all env variables set"); process.exit(); } From c67fc8aa756b9708722bf9a1e8185043b4d7ee6c Mon Sep 17 00:00:00 2001 From: overtorment Date: Sun, 15 Dec 2024 14:23:19 +0000 Subject: [PATCH 4/5] FIX: FCM pushes fixed due to deprecation of legacy api --- src/class/GroundControlToMajorTom.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/class/GroundControlToMajorTom.ts b/src/class/GroundControlToMajorTom.ts index 95ea01c..a404300 100644 --- a/src/class/GroundControlToMajorTom.ts +++ b/src/class/GroundControlToMajorTom.ts @@ -1,10 +1,10 @@ -import {GoogleAuth} from "google-auth-library"; -import {DataSource} from "typeorm"; -import {PushLog} from "../entity/PushLog"; -import {TokenToAddress} from "../entity/TokenToAddress"; -import {TokenToHash} from "../entity/TokenToHash"; -import {TokenToTxid} from "../entity/TokenToTxid"; -import {components} from "../openapi/api"; +import { GoogleAuth } from "google-auth-library"; +import { DataSource } from "typeorm"; +import { PushLog } from "../entity/PushLog"; +import { TokenToAddress } from "../entity/TokenToAddress"; +import { TokenToHash } from "../entity/TokenToHash"; +import { TokenToTxid } from "../entity/TokenToTxid"; +import { components } from "../openapi/api"; const jwt = require("jsonwebtoken"); const http2 = require("http2"); require("dotenv").config(); From f76a2715562dd7316e2dde437089fd61d883e52a Mon Sep 17 00:00:00 2001 From: overtorment Date: Sun, 15 Dec 2024 14:29:42 +0000 Subject: [PATCH 5/5] FIX: FCM pushes fixed due to deprecation of legacy api --- tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/tsconfig.json b/tsconfig.json index b2e30e8..f016eb9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "skipLibCheck": true, "lib": ["es5", "es6"], "target": "es5", "module": "commonjs",