This commit is contained in:
Overtorment 2020-07-29 13:07:19 +01:00
parent 83ec9f99c0
commit b2fab80630
5 changed files with 21 additions and 44 deletions

View File

@ -1,3 +1,3 @@
{
"printWidth": 160
"printWidth": 230
}

View File

@ -66,7 +66,7 @@
## Can you hear me, Major Tom?
Push notifications server for bitcoin wallets. Processes blocks & mempool in search of subscribed onchain addresses.
Built with typescript, expressjs, mariadb & openapi.
Built with typescript, expressjs, mariadb & [openapi](https://editor.swagger.io/?url=https://raw.githubusercontent.com/BlueWallet/GroundControl/master/openapi.yaml).
In memory of David Bowie
@ -92,6 +92,7 @@ Set them as env variables or put them into `.env` file in project root dir.
- `FCM_SERVER_KEY` hex encoded
- `APNS_PEM` hex encoded
- `BITCOIN_RPC` for example `http://username:password@host:8332`
- `APNS_TOPIC` for example `io.bluewallet.bluewallet`
### License

View File

@ -5,6 +5,8 @@ info:
version: 0.0.8
servers:
- url: http://localhost:3001
- url: https://groundcontrol-bluewallet-stg.herokuapp.com
- url: https://groundcontrol-bluewallet.herokuapp.com
paths:
/lightningInvoiceGotSettled:
post:

View File

@ -17,11 +17,7 @@ const http2 = require("http2");
* @see https://firebase.google.com/docs/cloud-messaging/http-server-ref
*/
export class GroundControlToMajorTom {
static async pushOnchainAddressGotUnconfirmedTransaction(
serverKey: string,
apnsPem: string,
pushNotification: Components.Schemas.PushNotificationOnchainAddressGotUnconfirmedTransaction
): Promise<[object, object]> {
static async pushOnchainAddressGotUnconfirmedTransaction(serverKey: string, apnsPem: string, pushNotification: Components.Schemas.PushNotificationOnchainAddressGotUnconfirmedTransaction): Promise<[object, object]> {
const fcmPayload = {
data: {},
notification: {
@ -45,15 +41,10 @@ export class GroundControlToMajorTom {
};
if (pushNotification.os === "android") return GroundControlToMajorTom._pushToFcm(serverKey, pushNotification.token, fcmPayload, pushNotification);
if (pushNotification.os === "ios")
return GroundControlToMajorTom._pushToApns(apnsPem, pushNotification.token, apnsPayload, pushNotification, pushNotification.txid);
if (pushNotification.os === "ios") return GroundControlToMajorTom._pushToApns(apnsPem, pushNotification.token, apnsPayload, pushNotification, pushNotification.txid);
}
static async pushOnchainTxidGotConfirmed(
serverKey: string,
apnsPem: string,
pushNotification: Components.Schemas.PushNotificationTxidGotConfirmed
): Promise<[object, object]> {
static async pushOnchainTxidGotConfirmed(serverKey: string, apnsPem: string, pushNotification: Components.Schemas.PushNotificationTxidGotConfirmed): Promise<[object, object]> {
const fcmPayload = {
data: {},
notification: {
@ -77,15 +68,10 @@ export class GroundControlToMajorTom {
};
if (pushNotification.os === "android") return GroundControlToMajorTom._pushToFcm(serverKey, pushNotification.token, fcmPayload, pushNotification);
if (pushNotification.os === "ios")
return GroundControlToMajorTom._pushToApns(apnsPem, pushNotification.token, apnsPayload, pushNotification, pushNotification.txid);
if (pushNotification.os === "ios") return GroundControlToMajorTom._pushToApns(apnsPem, pushNotification.token, apnsPayload, pushNotification, pushNotification.txid);
}
static async pushOnchainAddressWasPaid(
serverKey: string,
apnsPem: string,
pushNotification: Components.Schemas.PushNotificationOnchainAddressGotPaid
): Promise<[object, object]> {
static async pushOnchainAddressWasPaid(serverKey: string, apnsPem: string, pushNotification: Components.Schemas.PushNotificationOnchainAddressGotPaid): Promise<[object, object]> {
const fcmPayload = {
data: {},
notification: {
@ -109,15 +95,10 @@ export class GroundControlToMajorTom {
};
if (pushNotification.os === "android") return GroundControlToMajorTom._pushToFcm(serverKey, pushNotification.token, fcmPayload, pushNotification);
if (pushNotification.os === "ios")
return GroundControlToMajorTom._pushToApns(apnsPem, pushNotification.token, apnsPayload, pushNotification, pushNotification.txid);
if (pushNotification.os === "ios") return GroundControlToMajorTom._pushToApns(apnsPem, pushNotification.token, apnsPayload, pushNotification, pushNotification.txid);
}
static async pushLightningInvoicePaid(
serverKey: string,
apnsPem: string,
pushNotification: Components.Schemas.PushNotificationLightningInvoicePaid
): Promise<[object, object]> {
static async pushLightningInvoicePaid(serverKey: string, apnsPem: string, pushNotification: Components.Schemas.PushNotificationLightningInvoicePaid): Promise<[object, object]> {
const fcmPayload = {
data: {},
notification: {
@ -141,18 +122,12 @@ export class GroundControlToMajorTom {
};
if (pushNotification.os === "android") return GroundControlToMajorTom._pushToFcm(serverKey, pushNotification.token, fcmPayload, pushNotification);
if (pushNotification.os === "ios")
return GroundControlToMajorTom._pushToApns(apnsPem, pushNotification.token, apnsPayload, pushNotification, pushNotification.hash);
if (pushNotification.os === "ios") return GroundControlToMajorTom._pushToApns(apnsPem, pushNotification.token, apnsPayload, pushNotification, pushNotification.hash);
}
protected static async _pushToApns(
apnsPem: string,
token: string,
apnsPayload: object,
pushNotification: Components.Schemas.PushNotificationBase,
collapseId
): Promise<[object, object]> {
protected static async _pushToApns(apnsPem: string, token: string, apnsPayload: object, pushNotification: Components.Schemas.PushNotificationBase, collapseId): Promise<[object, object]> {
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)) {
if (["token", "os", "badge"].includes(dataKey)) continue;
apnsPayload["data"][dataKey] = pushNotification[dataKey];
@ -165,7 +140,7 @@ export class GroundControlToMajorTom {
client.on("error", (err) => console.error(err));
const headers = {
":method": "POST",
"apns-topic": "io.bluewallet.bluewallet",
"apns-topic": process.env.APNS_TOPIC,
"apns-collapse-id": collapseId,
"apns-expiration": Math.floor(+new Date() / 1000 + 3600 * 24),
":scheme": "https",
@ -206,12 +181,7 @@ export class GroundControlToMajorTom {
});
}
protected static async _pushToFcm(
serverKey: string,
token: string,
fcmPayload: object,
pushNotification: Components.Schemas.PushNotificationBase
): Promise<[object, object]> {
protected static async _pushToFcm(serverKey: string, token: string, fcmPayload: object, pushNotification: Components.Schemas.PushNotificationBase): Promise<[object, object]> {
const _api = new Frisbee({ baseURI: "https://fcm.googleapis.com" });
fcmPayload["to"] = token;

View File

@ -8,6 +8,10 @@ require("dotenv").config();
const cors = require("cors");
const url = require("url");
const parsed = url.parse(process.env.JAWSDB_MARIA_URL);
if (!process.env.JAWSDB_MARIA_URL || !process.env.FCM_SERVER_KEY || !process.env.APNS_PEM || !process.env.APNS_TOPIC) {
console.error("not all env variables set");
process.exit();
}
createConnection({
type: "mariadb",