{"id":15016648,"url":"https://github.com/mastodon/webpush-apn-relay","last_synced_at":"2025-10-06T14:31:52.715Z","repository":{"id":65984672,"uuid":"378137383","full_name":"mastodon/webpush-apn-relay","owner":"mastodon","description":"Relay that forwards web push notifications to APNs.","archived":false,"fork":true,"pushed_at":"2024-09-18T13:47:52.000Z","size":513,"stargazers_count":12,"open_issues_count":1,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-22T20:14:54.078Z","etag":null,"topics":["apns","mastodon","webpush"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"DagAgren/toot-relay","license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mastodon.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-06-18T12:04:16.000Z","updated_at":"2024-11-05T01:05:15.000Z","dependencies_parsed_at":"2023-02-19T19:31:26.377Z","dependency_job_id":null,"html_url":"https://github.com/mastodon/webpush-apn-relay","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mastodon%2Fwebpush-apn-relay","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mastodon%2Fwebpush-apn-relay/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mastodon%2Fwebpush-apn-relay/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mastodon%2Fwebpush-apn-relay/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mastodon","download_url":"https://codeload.github.com/mastodon/webpush-apn-relay/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235531112,"owners_count":19004901,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["apns","mastodon","webpush"],"created_at":"2024-09-24T19:49:11.689Z","updated_at":"2025-10-06T14:31:47.433Z","avatar_url":"https://github.com/mastodon.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# toot-relay #\n\nThis is a small service, written in Go, that can be set as an endpoint for web\npush notifications, and forwards the encrypted payloads it receives to an iOS\napp through APNs. It is designed to forward notifications from Mastodon to\nthe iOS client Toot!, but may be of use in other cases too.\n\n## Usage ##\n\nRun `go build`, run `./toot-relay`. It will listen on port 42069. Subscribe to web\npushes using the endpoint\n`http://\u003cyour-domain-name\u003e:42069/relay-to/\u003cenvironment\u003e/\u003cdevice-token\u003e[/extra]`,\nwhere `\u003cenvironment\u003e` is either `development` or `production`, `\u003cdevice-token\u003e`\nis the hex encoded device token for the device to push to, and `extra` is any\nextra information you want relayed back to your client.\n\nYou will need a push notification certificate, which should be put in the same\ndirectory, named `toot-relay.p12`. With a production certificate, both pushing\nto production and development environments works. With a development certificate,\nonly development will work.\n\n## Docker ##\n\nA simple Dockerfile is included for running the service containerised. It has been\ntested with the following hosting solutions:\n\n* [Zeit Now](https://zeit.co/now) - There is also a configuration file (`now.json`)\n  for using this service to host it. It requites adding the p12 file as a base 64\n  encoded secret: `now secrets add p12-base64 \"$(cat toot-relay.p12 | base64)`\n* [Heroku](https://heroku.com/) - Add a configuration var named `P12_BASE64`\n  containing the base 64 encoded p12 file.\n\n## Status ##\n\nThis is a fairly minimal implementation of only the parts of RFC 8030 that are\nrequired to relay push notifications from Mastodon. It only supports the simple\nPOST requests, and not async requests with receipts.\n\nIt does support the various headers, such as `TTL:`, `Urgency:`, and `Topic:`,\nwhich are converted into expiration time, priority (`very-low` and `low` are 5,\n`high` and `very-high` are 10), and collapse ID.\n\nThe returned `Location:` header is nonsensical, but contains the APNs ID. I did\nnot read the spec closely enough to see if this address is actually used for\nanything, but I do not think it is needed by Mastodon.\n\nCurrently only `Content-Encoding: aesgcm` is supported. `aes128gcm` is trivial\nto support in this service, as it just needs to ignore the extra headers\n(`Encryption:` and `Crypto-Key:`) used by `aesgcm`, but my client-side code does\nnot support it and this it is rejected. If your client-side code can handle it,\nuncomment the line referring to it.\n\n## Configuration ##\n\n### Runtime Flags\n\n- `-max-queue-size`: sets the size of the channel that buffers incoming notifications. Raising this value will consume more RAM (Go will pre-allocate the entire buffer to hold `N * size of message`). Defaults to `4096`.\n- `-max-workers`: sets the number of parallel goroutines that will send notifications to Apple. Raising it will drain the queue more quickly at a small cost to increased resource usage. Each goroutine uses gets approx. 2kb of memory. This can safely scale into the thousands, if needed. See [this post](https://tpaschalis.github.io/goroutines-size/) for scaling considerations. Defaults to `8`.\n\n### Environment Variables\n\nThe service will read a few environment variables that let you make some adjustments.\n\n* `P12_FILENAME`: The name of the p12 file to use for the push notification certificate.\n  Defaults to `toot-relay.p12`.\n* `P12_BASE64`: Alternative, you can include the base64-encoded data for the entire p12\n  file in this variable. This is useful for hosting services that let you set\n  environment variables for secret values.\n* `P12_PASSWORD`: The password for the p12 file or base64 encoded data. Defaults to no\n  password.\n* `PORT`: The port to listen on. Defaults to `42069`.\n* `CRT_FILENAME`: The crt file to use for TLS connections. Defaults to `toot-relay.crt`.\n* `KEY_FILENAME`: The key file to use for TLS connections. Defaults to `toot-relay.key`.\n* `CA_FILENAME`: A file containing PEM encoded certificates that will override the system\n  root CAs when connecting to the Apple Notification Service API if set. Default: unset.\n\n## Receiving ##\n\nThe client needs to implement a user notification service extension that can\ndecrypt the payloads once they arrive. The original payload is transmitted in the\n`p` property of the notification. The server's public key is transmitted in `k`,\nthe cryptographic salt in `s`, and any extra value supplied in the push endpoint\nURL (the `extra` part as shown in the Usage section above) is passed in `x`.\n\n### Example ###\n\nAn [excerpt of the Toot! code base](iOS/) for receiving and decrypting messages\nis available. You can use this as a basis for your own implementation, or\nread on for more technical details of how to do it yourself.\n\n### Encoding ###\n\nThe fields `p`, `s` and `k` are transmitted using an extended variant of z85\nencoding. This encoding is the same as [ZeroMQ's z85 encoding][z85], but extended\nto support messages of any length, not just multiples of four bytes. It follows the\nspec suggested in [this message][z85ext], storing the last 1-3 bytes as 2-4 characters,\nrepresenting an 8, 16 or 24-bit integer similarly to how normal z85 encoding represents\n32-bit integers.\n\n[z85]: https://rfc.zeromq.org/spec:32/Z85/\n[z85ext]: http://grokbase.com/t/zeromq/zeromq-dev/144nd380c4/rfc-32-z85-requiring-frames-to-be-multiples-of-4-or-5-bytes\n\n## Regarding HTTPS ##\n\nMastodon, and possibly others, force SSL when connecting to the push endpoint.\nThe service does have rudimentary support; put files named `toot-relay.crt` and\n`toot-relay.key` in the same directory, and those will be loaded and used to\nserve HTTPS instead of HTTP. (Also see the \"Configuration\" section.)\n\nIn practice, it may be easier to use ngnix or another service to handle HTTPS\ntraffic for you, and forward it to the service as plain HTTP.\n\n## License ##\n\nThis code is released into the public domain with no warranties. If that is not\nsuitable, it is also available under the\n[CC0 license](http://creativecommons.org/publicdomain/zero/1.0/).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmastodon%2Fwebpush-apn-relay","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmastodon%2Fwebpush-apn-relay","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmastodon%2Fwebpush-apn-relay/lists"}