heart-sms-backend
This project provides a database and API backend for HeartSMS, a fork of PulseSMS. Written with NodeJS.
Heart is a text messaging app for android that lets you text from your browser on any computer. Whenever you receive or send a text on your phone, it is encrypted (along with certain metadata) on the client, sent to the backend (this repo), and stored in a database. The web client can use this database via its associated API (plus websockets via Gotify) to read and respond to SMS messages in real time from any modern browser. When you hit send in the browser, it sends a request (via Gotify/UnifiedPush) to your android phone to actually send the message. This means that you keep your phone number.
Your messages are yours. Heart does not collect any analytics data (or any data whatsoever), and the backend is meant to be self hosted.
None of this would be possible without the work of Luke Klinker and TChilderhose.
TChilderhose implemented so much of this backend (in C#) before giving me his code to use for reference. Thank you!
Check the TODO.md
file for current state and future plans.
Eventually the rebranded Heart SMS app will be released on F-Droid, etc.
The end goal is a docker-compose file that can be initialized with environment variables, including the web client. Native clients will have preferences added to set the base url of the API.
Heart does not use Firebase Messaging. Instead, it uses Gotify/UnifiedPush, which is accessible via websockets for the web client.
Build and run
For a detailed guide, see Getting Started
Here's the short version:
- Clone the repo
- Quickly create your
api
anddb
env files - Generate certificates using certbot (or your own CA for testing)
- Update URLs and cert paths in Caddyfile
docker-compose up -d
Development server
Follow the steps in Contributing to HeartSMS to set up a development server for tinkering.
Docker
This project uses 3 bespoke containers (plus a Gotify container and a Caddy container) to make configuration easy. Just create/edit the .db.env
and .api.env
files, add the certs and you're ready to go!
If you want to build the production containers yourself (might be a good idea if you are testing certain things because I don't have CI/CD in place... yet), you can do so in the following way:
Build backend and database simultaneously
Builds both images at once with tag :dev
npm run build-dev
heart-sms-backend
From project root, run:
npm run docker:build
This will create an image tagged heartsms/heart-sms-backend:dev
.
heart-sms-web
Clone the heart-sms-web
repo, then run from web project root:
npm run docker:build
This will create an image tagged heartsms/heart-sms-web:dev
.
heart-sms-db
npm run db:build
This will create an image tagged heartsms/heart-sms-db:dev
.
The following is from TChilderhose (edited)
TChilderhose put a lot of work in to a C# backend, and gave me the confidence to take this on. Thanks!
When Pulse SMS was bought by Maple Media, I started working on a backend that I could selfhost and just fork the android client, manually swap the urls and keys and use that.
Eventually Maple Media made the repo private, so I stopped working on it because I don't have time to do upkeep on the android side of stuff. So I figured I would dump my findings and some initial code that I was working on.
Findings
pulse-sms-android
- There are inconsistencies with naming and case. Sometimes it expects camelcase, sometimes it expect snake case
- (THIS HAS BEEN FIXED IN HEARTSMS) It does seem to be E2EE, but the
api/v1/accounts/signup
andapi/v1/accounts/login
are sending the password in plain text... So in theory they could be storing that password when you login, and then they have everything they need (password and salt2) to decrypt the messages. My recommendation would be to first hash the password on the client when sending the signup and login requests (continue to hash it on the server as well) and continue to use the raw password withsalt2
to generate the E2EE key. That way the server can't decrypt the messages no matter what. - (HEARTSMS USES PURE WEBSOCKETS, NOT FIREBASE) It uses Firebase data messages to share data between clients. It works well, but also means it's reliant on Google services
Setup
pulse-sms-android
- Most likely you'll be starting out without any certificate on your webserver, so android will need some config to allow that.
Add the file
pulse-sms-android\app\src\main\res\xml\security_config.xml
withand add<?xml version="1.0" encoding="utf-8"?> <network-security-config> <base-config cleartextTrafficPermitted="true"> <trust-anchors> <certificates src="system" /> </trust-anchors> </base-config> </network-security-config>
android:networkSecurityConfig="@xml/security_config"
to thepulse-sms-android\app\src\main\AndroidManifest.xml
file in theapplication
block (around line 83) - In
pulse-sms-android\api\src\main\java\xyz\klinker\messenger\api\Api.java
replaceAPI_DEBUG_URL
orAPI_RELEASE_URL
with the url you are going to be using. I sayAPI_RELEASE_URL
because a bunch of code needs to be uncommented/changed to get the debug url to be used. - For Firebase, there are a lot of guides around, to set it up in the google console. But the idea is you set it up, grab the
google-services.json
it gives you and replace all of them in the app you can find. You will also need ot replace theFIREBASE_STORAGE_URL
inpulse-sms-android\api_implementation\src\main\java\xyz\klinker\messenger\api\implementation\ApiUtils.kt
- Go to
pulse-sms-android\api_implementation\src\main\java\xyz\klinker\messenger\api\implementation\LoginActivity.java
and insetUpInitialLayout
comment out the if statement in there so that it doesn't disable signups (eventually I was going to strip all of the IAP code)
- Most likely you'll be starting out without any certificate on your webserver, so android will need some config to allow that.
Add the file