This is a NodeJS-based web service, which wraps Googles Firebase Messaging Service, so we can hide the server secret key. Server secret key must be placed in the environment variable FIREBASE_SERVER_SECRET.
This server was generated by the swagger-codegen project. By using the OpenAPI-Spec from a remote server, you can easily generate a server stub.
To run the server, run:
npm start
To view the Swagger UI interface:
open http://localhost:8080/docs
This project leverages the mega-awesome swagger-tools middleware which does most all the work.
The server uses the node-uuid
package to generate UUIDs.
The /service
directory are where most of the work is happening and have the skeleton methods invoked over HTTP as functions.
Most of this skeletal implementation is in /service/MessageService.js
and /service/ConnectionService.js
.
ConnectionService currently just generates a UUID used as the topic subscription for two devices to connect with. The UUID is transitory and not stored.
MessageService handles the outbound communication to Google's Firebase Cloud Messaging platform.
messagesPOST
is the main method implemented. It expects a JSON payload and extracts a recipient_id
from it, which will be either
- Another device's FCM
registration_id
, issued when the device signs on to FCM - A topic, of the format
topics/topic_name
, which will broadcast to any devices subscribing to this topic.
The payload is wrapped inside an object (fullPayload
) which has properties added to ensure it is sent as a notification that can appear for and allow the waking of an application running in the background. The notification format added to fullPayload
is copied from the notifications
array, which uses the indexed item matching the message_type
property of the invocation payload object, allowing different types of notification, based on the message type.
This server-based interface exists primarily because whilst device-to-device messaging is possible, it exposes a server application key in the Application. To send a message through FCM, the HTTP connection must authenticate using an Application Key, which cannot be regenerated and is locked to
The server application key is unique per-application and cannot be reissued or revoked in case of a leak, which is why we use our server to pass the communications upstream to Google -- it means our mobile application does not have to store this secret application key, which removes one exploitation vector.
To set the secret application key, you must define the environment variable: FIREBASE_SERVER_SECRET
If you are debugging locally, using VisualStudio Code, you can define envirnment variables in the /.vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"program": "${workspaceFolder}/index.js",
"env": {
"PORT": "8003",
"FIREBASE_SERVER_SECRET" : "UNSET"
}
}
]
}
If you are deploying to heroku, simply define the environment variable "FIREBASE_SERVER_SECRET" in the 'settings' for your application.
The one problem with the lovely swagger tools, is they they define the swagger.yaml with the host address and port. This is necessary, because the swagger ui SPWA (which is used to document the API directly from the server) reads it to discover the address to send http requests to. This makes it a pain when doing deployments: For each deployment, the swagger.yaml has to be changed in the repo, so that the swagger ui has the right address defined.
To get around this, we use an environment variable: CONSUMER_API_ADDRESS, into which we put the domain of the heroku application. e.g. rescuestationpush.herokuapp.com. This value is then written to the YAML file when the app is deployed.
When deploying locally, you can use the /.vscode/launch.json, as above, to specify localhost. If you leave it out, the YAML will be populated with the IP address of the server.
Note: this method does not modify the 'scheme' value of YAML You will have to set this to either http (local) or https (deployed).