let traefik handle CORS
This commit is contained in:
82
README.md
82
README.md
@@ -15,7 +15,6 @@ It's designed to be run as a Docker container and integrated with Traefik v3 for
|
||||
* Integrates with Traefik v3 via Docker labels.
|
||||
* Configurable via environment variables (`.env` file).
|
||||
* Optional Basic Authentication for securing the `/webhook` and `/subscribe` endpoints.
|
||||
* CORS configuration for allowing requests (needed if your PWA management interface interacts with the `/subscribe` endpoint).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@@ -61,21 +60,16 @@ It's designed to be run as a Docker container and integrated with Traefik v3 for
|
||||
* `VAPID_PRIVATE_KEY`: The private key generated in step 2. **Keep this secret!**
|
||||
* `VAPID_SUBJECT`: A `mailto:` or `https:` URL identifying you or your application (e.g., `mailto:admin@yourdomain.com`). Used by push services to contact you.
|
||||
* `PORT`: (Default: `3000`) The internal port the Node.js app listens on. Traefik will map to this.
|
||||
* `SUBSCRIPTIONS_FILE`: (Default: `/app/subscriptions.json`) The path *inside the container* where the button-to-subscription mapping is stored.
|
||||
* `SUBSCRIPTIONS_FILE`: (Default: `subscriptions.json`) The path *inside the container* where the button-to-subscription mapping is stored.
|
||||
* `DEFAULT_BUTTON_NAME`: (Default: `game-button`) The default button name to use when the `Button-Name` header is not provided in the webhook request.
|
||||
* `BASIC_AUTH_USERNAME`: (Optional) Username for Basic Authentication. If set along with `BASIC_AUTH_PASSWORD`, authentication will be enabled for `/webhook` and `/subscribe`.
|
||||
* `BASIC_AUTH_PASSWORD`: (Optional) Password for Basic Authentication. If set along with `BASIC_AUTH_USERNAME`, authentication will be enabled.
|
||||
* `ALLOWED_ORIGINS`: Comma-separated list of domains allowed by CORS. Include your PWA's domain if it needs to interact directly (e.g., for setup). Example: `https://my-pwa.com`.
|
||||
* `ALLOWED_METHODS`: (Default: `POST,OPTIONS`) Standard methods needed.
|
||||
* `ALLOWED_HEADERS`: (Default: `Content-Type,Authorization`) Standard headers needed.
|
||||
* `NOTIFICATION_MAX_RETRIES`: (Default: `3`) Number of retry attempts for failed push notifications. Must be a number.
|
||||
* `NOTIFICATION_FIRST_RETRY_DELAY_MS`: (Default: `10`) Delay in milliseconds for the first retry attempt. Setting to 0-10ms provides near-immediate first retry for transient DNS issues. Must be a number.
|
||||
* `NOTIFICATION_SUBSEQUENT_RETRY_DELAY_MS`: (Default: `1000`) Base delay in milliseconds for subsequent retries. Each additional retry uses this value with exponential backoff and jitter. Must be a number.
|
||||
* `DNS_TIMEOUT_MS`: (Default: `5000`) DNS resolution timeout in milliseconds. Must be a number.
|
||||
* `HTTP_TIMEOUT_MS`: (Default: `10000`) HTTP request timeout in milliseconds. Must be a number.
|
||||
* `LOG_LEVEL`: (Default: `info`) Controls verbosity of logs. Valid values are `error`, `warn`, `info`, or `debug`. Use `debug` to see detailed header information and other diagnostic messages.
|
||||
* `TRAEFIK_SERVICE_HOST`: Your public domain for this service (e.g., `webpush.virtonline.eu`).
|
||||
* `TRAEFIK_CERT_RESOLVER`: The name of your TLS certificate resolver configured in Traefik (e.g., `le`, `myresolver`).
|
||||
|
||||
4. **Configure Traefik Labels:**
|
||||
* Copy the example `labels` file:
|
||||
@@ -83,24 +77,6 @@ It's designed to be run as a Docker container and integrated with Traefik v3 for
|
||||
cp labels.example labels
|
||||
```
|
||||
|
||||
5. **Prepare Subscription Mapping File:**
|
||||
* Edit the `subscriptions.json` file
|
||||
* Add entries mapping your Flic button's serial number (as a lowercase string key) to the PWA `PushSubscription` object.
|
||||
```json
|
||||
{
|
||||
"game": { // <-- Replace with your actual Flic Button name (lowercase recommended)
|
||||
"endpoint": "https://your_pwa_push_endpoint...",
|
||||
"expirationTime": null,
|
||||
"keys": {
|
||||
"p256dh": "YOUR_PWA_SUBSCRIPTION_P256DH_KEY",
|
||||
"auth": "YOUR_PWA_SUBSCRIPTION_AUTH_KEY"
|
||||
}
|
||||
}
|
||||
// Add more entries for other buttons if needed
|
||||
}
|
||||
```
|
||||
* Ensure this file contains valid JSON.
|
||||
|
||||
## Running the Service
|
||||
|
||||
1. **Build the Docker Image:**
|
||||
@@ -113,7 +89,7 @@ It's designed to be run as a Docker container and integrated with Traefik v3 for
|
||||
This command runs the container in detached mode (`-d`), names it, connects it to the `traefik` network, passes environment variables from the `.env` file, applies the Traefik labels from the `labels` file, and mounts the `subscriptions.json` file into the container.
|
||||
|
||||
```bash
|
||||
docker run -d --name flic-webhook-webpush \
|
||||
docker run -rm -d --name flic-webhook-webpush \
|
||||
--network traefik \
|
||||
--env-file .env \
|
||||
--label-file labels \
|
||||
@@ -137,15 +113,19 @@ In your Flic app or Flic Hub SDK interface:
|
||||
1. Select your Flic button.
|
||||
2. Add an "Internet Request" action.
|
||||
3. Fill in the following details:
|
||||
* Set `GET` method.
|
||||
* Select the `GET` method.
|
||||
* Set URL with query parameter: `https://<your_domain>/webhook/SingleClick` (Replace `<your_domain>` with your actual service domain, e.g., `webpush.virtonline.eu`).
|
||||
* **If Basic Authentication is enabled:**
|
||||
* Set the `Username` and `Password` fields to the values from your `BASIC_AUTH_USERNAME` and `BASIC_AUTH_PASSWORD` environment variables.
|
||||
* **If Basic Authentication is disabled:**
|
||||
* Leave the `Username` and `Password` fields empty.
|
||||
* Tap on `Save action`.
|
||||
4. Repeat for Double Click and/or Hold events, changing the `click_type` parameter accordingly (e.g., `/DoubleClick`).
|
||||
* Set the Headers:
|
||||
* Set the `Key` fields to `Authorization`.
|
||||
* Set the `Value` fields to `Basic <base64 encoded username:password>`.
|
||||
* Click `ADD`.
|
||||
* Tap on `SAVE ACTION`.
|
||||
4. Repeat for Double Click (i.e., `/DoubleClick`) and Hold (i.e., `/Hold`) events.
|
||||
The request for the Hold event should look like this:
|
||||
|
||||
<img src="images/flic-button-request.png" width="300" alt="Flic Button Request">
|
||||
|
||||
## API Endpoints
|
||||
|
||||
* **`POST /subscribe`**
|
||||
@@ -184,13 +164,12 @@ In your Flic app or Flic Hub SDK interface:
|
||||
* `Timestamp`: Timestamp of the button event (sent by the Flic system).
|
||||
* `Button-Battery-Level`: The battery level percentage of the button (sent by the Flic system).
|
||||
* **Push Notification Payload (`data` field):** The service sends a JSON payload within the push notification. The client-side Service Worker can access this data via `event.data.json()`. The structure is:
|
||||
```json
|
||||
{
|
||||
"action": "SingleClick", // or DoubleClick, Hold
|
||||
"button": "game-button", // Normalized button name (lowercase)
|
||||
"timestamp": "2024-03-28T15:00:00.000Z", // ISO 8601 timestamp or current server time
|
||||
"batteryLevel": 100 // Integer percentage (0-100) or 'N/A' if not provided
|
||||
}
|
||||
```bash
|
||||
curl -X GET https://webpush.virtonline.eu/webhook/SingleClick \
|
||||
-H 'Authorization: Basic cGxheWVyOlNldmVuT2ZOaW5l' \
|
||||
-H "Button-Name: Game-button" \
|
||||
-H "Timestamp: 2025-03-26T01:10:20Z" \
|
||||
-H "Button-Battery-Level: 100"
|
||||
```
|
||||
* **Responses:**
|
||||
* `200 OK`: Webhook received, push notification sent successfully.
|
||||
@@ -204,25 +183,14 @@ In your Flic app or Flic Hub SDK interface:
|
||||
|
||||
Once your service is up and running, you can test the webhook endpoint using curl or any API testing tool. This example assumes Basic Authentication is enabled.
|
||||
|
||||
**Note:** Replace `<username>`, `<password>`, `<your_domain>`, and `<button_name>` with your actual values. The `Button-Name` header is optional and will default to the value of `DEFAULT_BUTTON_NAME` if not provided.
|
||||
**Note:** Replace `<username>`, `<password>` with your actual values. The `Button-Name` header is optional and will default to the value of `DEFAULT_BUTTON_NAME` if not provided.
|
||||
|
||||
```bash
|
||||
# Generate Base64 credentials (run this once)
|
||||
# echo -n '<username>:<password>' | base64
|
||||
|
||||
# Example using generated Base64 string (replace YOUR_BASE64_CREDS)
|
||||
curl -X GET "https://<your_domain>/webhook/SingleClick" \
|
||||
-H "Authorization: Basic YOUR_BASE64_CREDS" \
|
||||
-H "Button-Name: <button_name>" \
|
||||
-H "Timestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
||||
-H "Button-Battery-Level: 100" \
|
||||
|
||||
# Example using curl's built-in Basic Auth (-u)
|
||||
curl -X GET "https://<your_domain>/webhook/SingleClick" \
|
||||
-u "<username>:<password>" \
|
||||
-H "Button-Name: <button_name>" \
|
||||
-H "Timestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
||||
-H "Button-Battery-Level: 100" \
|
||||
curl -X GET "https://webpush.virtonline.eu/webhook/SingleClick" \
|
||||
-H "Authorization: Basic $(echo -n 'user:password' | base64)" \
|
||||
-H "Button-Name: game-button" \
|
||||
-H "Timestamp: $(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
||||
-H "Button-Battery-Level: 100"
|
||||
```
|
||||
|
||||
The expected response should be:
|
||||
@@ -232,7 +200,7 @@ The expected response should be:
|
||||
|
||||
If successful, the above response indicates that:
|
||||
1. Your webhook endpoint is properly configured
|
||||
2. The button ID was found in your subscriptions.json file
|
||||
2. The button name was found in your subscriptions.json file
|
||||
3. The web push notification was successfully sent to the registered PUSH API endpoint (e.g. https://jmt17.google.com/fcm/send/cf907M...)
|
||||
|
||||
If you receive a different response, refer to the Troubleshooting section below.
|
||||
|
||||
Reference in New Issue
Block a user