default button name

This commit is contained in:
cpu
2025-03-28 17:51:25 +01:00
parent 5a3b4974c4
commit 058441b6e6
4 changed files with 27 additions and 19 deletions

View File

@@ -9,6 +9,7 @@ VAPID_SUBJECT=mailto:mailto:admin@virtonline.eu # Contact email/URL for push ser
# --- Server Configuration ---
PORT=3000 # Internal port for the Node.js app
SUBSCRIPTIONS_FILE=subscriptions.json # Path inside the container
DEFAULT_BUTTON_NAME=game-button # Default button name to use when not specified
# --- Authentication (Optional) ---
# If both USERNAME and PASSWORD are set, Basic Auth will be enabled for:

View File

@@ -62,6 +62,7 @@ It's designed to be run as a Docker container and integrated with Traefik v3 for
* `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.
* `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`.
@@ -150,11 +151,11 @@ In your Flic app or Flic Hub SDK interface:
* **Description:** Adds or updates the Web Push subscription associated with a specific Flic button ID.
* **Authentication:** Optional Basic Authentication via `Authorization` header if `BASIC_AUTH_USERNAME` and `BASIC_AUTH_PASSWORD` are configured.
* **Request Body:** JSON object containing:
* `button_id` (string, required): The unique identifier for the Flic button (lowercase recommended, e.g., "game", "lights").
* `button_id` (string, optional): The unique identifier for the Flic button (lowercase recommended, e.g., "game-button", "lights-button"). If not provided, the value of `DEFAULT_BUTTON_NAME` environment variable will be used as a fallback.
* `subscription` (object, required): The [PushSubscription object](https://developer.mozilla.org/en-US/docs/Web/API/PushSubscription) obtained from the browser's Push API.
```json
{
"button_id": "game",
"button_id": "game-button", // Optional, defaults to DEFAULT_BUTTON_NAME environment variable
"subscription": {
"endpoint": "https://your_pwa_push_endpoint...",
"expirationTime": null,
@@ -167,7 +168,7 @@ In your Flic app or Flic Hub SDK interface:
```
* **Responses:**
* `201 Created`: Subscription saved successfully.
* `400 Bad Request`: Missing or invalid `button_id` or `subscription` object in the request body.
* `400 Bad Request`: Missing or invalid `subscription` object in the request body.
* `401 Unauthorized`: Missing or invalid Basic Authentication credentials (if authentication is enabled).
* `500 Internal Server Error`: Failed to save the subscription to the file.
@@ -177,7 +178,7 @@ In your Flic app or Flic Hub SDK interface:
* **URL Parameters:**
* `click_type` (required): The type of button press (e.g., `SingleClick`, `DoubleClick`, or `Hold`).
* **Required Headers:**
* `Button-Name` (required): The identifier of the Flic button (sent by the Flic system).
* `Button-Name`: The identifier of the Flic button (sent by the Flic system). If not provided, the value of `DEFAULT_BUTTON_NAME` environment variable will be used as a fallback.
* **Optional Headers:**
* `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).
@@ -202,7 +203,7 @@ 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.
**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.
```bash
# Generate Base64 credentials (run this once)

View File

@@ -14,6 +14,7 @@ const vapidPublicKey = process.env.VAPID_PUBLIC_KEY;
const vapidPrivateKey = process.env.VAPID_PRIVATE_KEY;
const vapidSubject = process.env.VAPID_SUBJECT; // mailto: or https:
const subscriptionsFilePath = process.env.SUBSCRIPTIONS_FILE || path.join(__dirname, 'subscriptions.json');
const defaultButtonName = process.env.DEFAULT_BUTTON_NAME || 'game-button';
// Basic Authentication Credentials
const basicAuthUsername = process.env.BASIC_AUTH_USERNAME;
const basicAuthPassword = process.env.BASIC_AUTH_PASSWORD;
@@ -233,20 +234,22 @@ const authenticateBasic = (req, res, next) => {
// Subscribe endpoint: Add a new button->subscription mapping
// Apply Basic Authentication
app.post('/subscribe', authenticateBasic, async (req, res) => {
const { button_id, subscription } = req.body;
let { button_id, subscription } = req.body;
logger.debug('All headers received:');
Object.keys(req.headers).forEach(headerName => {
logger.debug(` ${headerName}: ${req.headers[headerName]}`);
});
// If button_id is not provided, use defaultButtonName from environment variable
if (!button_id || typeof button_id !== 'string' || button_id.trim() === '') {
button_id = defaultButtonName;
logger.info(`No button_id provided, using default button name: ${button_id}`);
}
logger.info(`Received subscription request for button: ${button_id}`);
// Basic Validation
if (!button_id || typeof button_id !== 'string' || button_id.trim() === '') {
logger.warn('Subscription Error: Missing or invalid button_id');
return res.status(400).json({ message: 'Bad Request: Missing or invalid button_id' });
}
// Basic Validation - now we only validate subscription since button_id will use default if not provided
if (!subscription || typeof subscription !== 'object' || !subscription.endpoint || !subscription.keys || !subscription.keys.p256dh || !subscription.keys.auth) {
logger.warn('Subscription Error: Missing or invalid subscription object structure');
return res.status(400).json({ message: 'Bad Request: Missing or invalid subscription object' });
@@ -273,7 +276,7 @@ app.post('/subscribe', authenticateBasic, async (req, res) => {
// Apply Basic Authentication
app.get('/webhook/:click_type', authenticateBasic, async (req, res) => {
// Get buttonName from Header 'Button-Name' and timestamp from Header 'Timestamp'
const buttonName = req.headers['button-name'];
const buttonName = req.headers['button-name'] || defaultButtonName;
const timestamp = req.headers['timestamp'];
// Get click_type from URL path
const click_type = req.params.click_type;
@@ -291,9 +294,9 @@ app.get('/webhook/:click_type', authenticateBasic, async (req, res) => {
logger.info(`Received GET webhook: Button=${buttonName}, Type=${click_type}, Timestamp=${timestamp || 'N/A'}`);
// Basic validation
if (!buttonName || !click_type) {
logger.warn(`Webhook Error: Missing Button-Name header or click_type query parameter`);
return res.status(400).json({ message: 'Bad Request: Missing Button-Name header or click_type query parameter' });
if (!click_type) {
logger.warn(`Webhook Error: Missing click_type query parameter`);
return res.status(400).json({ message: 'Bad Request: Missing click_type query parameter' });
}
const normalizedButtonName = buttonName.toLowerCase(); // Use lowercase for lookup consistency

View File

@@ -7,17 +7,20 @@ DefaultDependencies=no
[Service]
Type=simple
Environment="HOME=/root"
Environment="APP_PATH=/virt/flic-webhook-webpush"
ExecStartPre=-/usr/bin/env sh -c '/usr/bin/env docker kill virt-flic-webhook-webpush 2>/dev/null || true'
ExecStartPre=-/usr/bin/env sh -c '/usr/bin/env docker rm virt-flic-webhook-webpush 2>/dev/null || true'
ExecStartPre=/usr/bin/env sh -c 'touch ${APP_PATH}/subscriptions.json'
ExecStart=/usr/bin/env docker run \
--rm \
--name=virt-flic-webhook-webpush \
--log-driver=none \
--network=traefik \
--env-file=/virt/flic-webhook-webpush/.env \
--label-file=/virt/flic-webhook-webpush/labels \
--mount type=bind,src=/virt/flic-webhook-webpush/subscriptions.json,dst=/app/subscriptions.json \
--env-file=${APP_PATH}/.env \
--label-file=${APP_PATH}/labels \
--mount type=bind,src=${APP_PATH}/subscriptions.json,dst=/app/subscriptions.json \
flic-webhook-webpush
ExecStop=-/usr/bin/env sh -c '/usr/bin/env docker kill virt-flic-webhook-webpush 2>/dev/null || true'