changed the route name
This commit is contained in:
78
server.js
78
server.js
@@ -14,7 +14,9 @@ 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 flicSecret = process.env.FLIC_SECRET; // Optional Bearer token secret for Flic webhook
|
||||
// Basic Authentication Credentials
|
||||
const basicAuthUsername = process.env.BASIC_AUTH_USERNAME;
|
||||
const basicAuthPassword = process.env.BASIC_AUTH_PASSWORD;
|
||||
// Note: We are NOT adding specific authentication for the /subscribe endpoint in this version.
|
||||
// Consider adding API key or other auth if exposing this publicly.
|
||||
const allowedOrigins = (process.env.ALLOWED_ORIGINS || "").split(',').map(origin => origin.trim()).filter(origin => origin);
|
||||
@@ -182,37 +184,55 @@ const corsOptions = {
|
||||
};
|
||||
app.use(cors(corsOptions));
|
||||
// Enable pre-flight requests for all relevant routes
|
||||
app.options('/flic-webhook', cors(corsOptions));
|
||||
app.options('/webhook', cors(corsOptions));
|
||||
app.options('/subscribe', cors(corsOptions));
|
||||
|
||||
|
||||
// --- Body Parsing Middleware ---
|
||||
app.use(express.json());
|
||||
|
||||
// --- Authentication Middleware (For Flic Webhook Only) ---
|
||||
const authenticateFlicRequest = (req, res, next) => {
|
||||
// Only apply auth if flicSecret is configured
|
||||
if (!flicSecret) {
|
||||
// --- Basic Authentication Middleware ---
|
||||
const authenticateBasic = (req, res, next) => {
|
||||
// Skip authentication for OPTIONS requests (CORS preflight)
|
||||
if (req.method === 'OPTIONS') {
|
||||
return next();
|
||||
}
|
||||
|
||||
// Skip authentication if username or password are not set in environment
|
||||
if (!basicAuthUsername || !basicAuthPassword) {
|
||||
logger.warn('Auth: Basic Auth username or password not configured. Skipping authentication.');
|
||||
return next();
|
||||
}
|
||||
|
||||
const authHeader = req.headers.authorization;
|
||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
logger.warn('Auth (Flic): Missing or malformed Authorization header');
|
||||
return res.status(401).json({ message: 'Unauthorized: Missing or malformed Bearer token' });
|
||||
|
||||
if (!authHeader || !authHeader.startsWith('Basic ')) {
|
||||
logger.warn('Auth: Missing or malformed Basic Authorization header');
|
||||
res.setHeader('WWW-Authenticate', 'Basic realm="Restricted Area"');
|
||||
return res.status(401).json({ message: 'Unauthorized: Basic Authentication required' });
|
||||
}
|
||||
|
||||
const token = authHeader.split(' ')[1];
|
||||
if (token !== flicSecret) {
|
||||
logger.warn('Auth (Flic): Invalid Bearer token received');
|
||||
return res.status(401).json({ message: 'Unauthorized: Invalid token' });
|
||||
}
|
||||
const credentials = authHeader.split(' ')[1];
|
||||
const decodedCredentials = Buffer.from(credentials, 'base64').toString('utf8');
|
||||
const [username, password] = decodedCredentials.split(':');
|
||||
|
||||
logger.debug('Auth (Flic): Request authenticated successfully.');
|
||||
next();
|
||||
// Note: Use constant-time comparison for production environments if possible,
|
||||
// but for this scope, direct comparison is acceptable.
|
||||
if (username === basicAuthUsername && password === basicAuthPassword) {
|
||||
logger.debug('Auth: Basic Authentication successful.');
|
||||
return next();
|
||||
} else {
|
||||
logger.warn('Auth: Invalid Basic Authentication credentials received.');
|
||||
res.setHeader('WWW-Authenticate', 'Basic realm="Restricted Area"');
|
||||
return res.status(401).json({ message: 'Unauthorized: Invalid credentials' });
|
||||
}
|
||||
};
|
||||
|
||||
app.post('/subscribe', async (req, res) => {
|
||||
// --- Routes ---
|
||||
|
||||
// Subscribe endpoint: Add a new button->subscription mapping
|
||||
// Apply Basic Authentication
|
||||
app.post('/subscribe', authenticateBasic, async (req, res) => {
|
||||
const { button_id, subscription } = req.body;
|
||||
|
||||
logger.debug('All headers received:');
|
||||
@@ -250,13 +270,17 @@ app.post('/subscribe', async (req, res) => {
|
||||
});
|
||||
|
||||
// --- Flic Webhook Endpoint (GET only) ---
|
||||
// Apply Flic-specific authentication to this route
|
||||
app.get('/flic-webhook', authenticateFlicRequest, 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 timestamp = req.headers['timestamp'];
|
||||
// Get click_type from query parameter instead of request body
|
||||
const click_type = req.query.click_type;
|
||||
// Get click_type from URL path
|
||||
const click_type = req.params.click_type;
|
||||
// Get battery level from Header 'Button-Battery-Level'
|
||||
const batteryLevelHeader = req.headers['button-battery-level'];
|
||||
// Use 'N/A' if header is missing or empty, otherwise parse as integer (or keep as string if parsing fails)
|
||||
const batteryLevel = batteryLevelHeader ? parseInt(batteryLevelHeader, 10) || batteryLevelHeader : 'N/A';
|
||||
|
||||
// Log all headers received from Flic
|
||||
logger.debug('All headers received:');
|
||||
@@ -289,7 +313,8 @@ app.get('/flic-webhook', authenticateFlicRequest, async (req, res) => {
|
||||
data: {
|
||||
action: click_type,
|
||||
button: normalizedButtonName, // Send normalized button name
|
||||
timestamp: timestamp || new Date().toISOString()
|
||||
timestamp: timestamp || new Date().toISOString(),
|
||||
batteryLevel: batteryLevel // Use the extracted value
|
||||
}
|
||||
// icon: '/path/to/icon.png'
|
||||
});
|
||||
@@ -324,8 +349,13 @@ server.listen(port, () => {
|
||||
logger.info(`Allowed Origins: ${allowedOrigins.length > 0 ? allowedOrigins.join(', ') : '(Any)'}`);
|
||||
logger.info(`Allowed Methods: ${allowedMethods.join(', ')}`);
|
||||
logger.info(`Allowed Headers: ${allowedHeaders.join(', ')}`);
|
||||
logger.info(`Flic Webhook Auth: ${flicSecret ? 'Enabled (Bearer Token)' : 'Disabled'}`);
|
||||
logger.info(`Subscription Endpoint Auth: Disabled`);
|
||||
// Log Basic Auth status instead of Flic Secret
|
||||
if (basicAuthUsername && basicAuthPassword) {
|
||||
logger.info('Authentication: Basic Auth Enabled');
|
||||
} else {
|
||||
logger.info('Authentication: Basic Auth Disabled (username/password not set)');
|
||||
}
|
||||
logger.info(`Subscription Endpoint Auth: ${basicAuthUsername && basicAuthPassword ? 'Enabled (Basic)' : 'Disabled'}`);
|
||||
logger.info(`Subscriptions File: ${subscriptionsFilePath}`);
|
||||
logger.info(`Push Notification Retry Config: ${maxRetries} retries, ${initialRetryDelay}ms initial delay`);
|
||||
logger.info(`DNS Config: IPv4 first, timeout ${dnsTimeout}ms`);
|
||||
|
||||
Reference in New Issue
Block a user