test page

This commit is contained in:
cpu
2025-03-29 04:37:06 +01:00
parent 832f19235f
commit ef96498cab
3 changed files with 354 additions and 55 deletions

View File

@@ -116,8 +116,13 @@ async function subscribeToPush() {
console.log('Notification permission granted.');
// After permission is granted, check for stored credentials or prompt user
// IMPORTANT: Force checking for credentials - even with an existing subscription
// Always allow the user to set/update credentials
let credentials = getBasicAuthCredentials();
const hasExistingCreds = !!credentials;
console.log('Has existing credentials:', hasExistingCreds);
// Ask for credentials every time unless one exists
if (!credentials) {
const confirmAuth = confirm('Do you want to set up credentials for push notifications now?');
if (!confirmAuth) {
@@ -136,6 +141,8 @@ async function subscribeToPush() {
const registration = await navigator.serviceWorker.ready;
let existingSubscription = await registration.pushManager.getSubscription();
let needsResubscribe = !existingSubscription;
console.log('Existing subscription found:', !!existingSubscription);
if (existingSubscription) {
const existingKey = existingSubscription.options?.applicationServerKey;
@@ -154,12 +161,18 @@ async function subscribeToPush() {
if (needsResubscribe) {
console.log('Subscribing for push notifications...');
const applicationServerKey = urlBase64ToUint8Array(getPublicVapidKey());
finalSubscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerKey
});
console.log('New push subscription obtained:', finalSubscription);
pushSubscription = finalSubscription; // Store it
try {
finalSubscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerKey
});
console.log('New push subscription obtained:', finalSubscription);
pushSubscription = finalSubscription; // Store it
} catch (subscribeError) {
console.error('Error subscribing to push:', subscribeError);
alert(`Failed to subscribe: ${subscribeError.message}`);
return;
}
}
if (!finalSubscription) {
@@ -262,22 +275,43 @@ export function handleFlicAction(action, buttonId, timestamp, batteryLevel) {
export function initPushFlic(handlers) {
actionHandlers = handlers; // Store the handlers passed from app.js
// Example: handlers = { SingleClick: handleNextPlayer, Hold: handleTogglePause }
// Attempt to subscribe immediately if permission might already be granted
// Or trigger subscription on a user action (e.g., a "Link Flic Button" button)
// For simplicity, let's try subscribing if SW is ready and permission allows
// Don't auto-subscribe - wait for user action
// This prevents issues with permission/notification prompts appearing unexpectedly
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
Notification.requestPermission().then(permission => {
if (permission === 'granted') {
console.log('[PushFlic] Permission granted, attempting subscription.');
subscribeToPush();
} else {
console.log('[PushFlic] Notification permission not granted.');
// Optionally provide a button for the user to trigger subscription later
}
});
// Check if permission is already granted, but don't automatically subscribe
if (Notification.permission === 'granted') {
console.log('[PushFlic] Permission already granted, but waiting for user action to subscribe.');
// Check if we have valid credentials
const hasCredentials = !!getBasicAuthCredentials();
console.log('[PushFlic] Has stored credentials:', hasCredentials);
} else {
console.log('[PushFlic] Notification permission not granted yet.');
}
});
}
}
// New function to manually trigger the subscription process
export function setupPushNotifications() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
console.log('[PushFlic] Manually triggering push subscription process...');
subscribeToPush();
});
} else {
console.error('[PushFlic] Service workers not supported, cannot subscribe');
alert('Your browser does not support push notifications.');
}
}
// Function to force re-authentication even if credentials exist
export function forceCredentialsPrompt() {
// Remove existing credentials to force new ones
localStorage.removeItem('basicAuthCredentials');
console.log('[PushFlic] Removed stored credentials, will prompt on next subscription attempt');
// Trigger the subscription process again
setupPushNotifications();
}

View File

@@ -16,15 +16,26 @@ export function initFlic() {
pushFlic.initPushFlic(flicActionHandlers);
}
export function handleServiceWorkerMessage(event) {
// Export functions for manually triggering push notifications setup
export function setupPushNotifications() {
pushFlic.setupPushNotifications();
}
export function forceCredentialsPrompt() {
pushFlic.forceCredentialsPrompt();
}
// --- Handle Messages from Service Worker ---
export function flicMessageHandler(event) {
// This function is passed to setupServiceWorker and called when a message arrives from the service worker
console.log('[App] Message received from Service Worker:', event.data);
if (event.data?.type === 'flic-action') {
// Check if this is a Flic action message
if (event.data && event.data.type === 'flic-action') {
const { action, button, timestamp, batteryLevel } = event.data;
if (flicActionHandlers[action]) {
flicActionHandlers[action]();
} else {
pushFlic.handleFlicAction(action, button, timestamp, batteryLevel);
}
// Pass to push-flic service to handle
pushFlic.handleFlicAction(action, button, timestamp, batteryLevel);
}
}
@@ -39,7 +50,7 @@ export function setupServiceWorker(messageHandler) {
// Listen for messages FROM the Service Worker (e.g., Flic actions)
navigator.serviceWorker.addEventListener('message', messageHandler);
// Initialize Flic integration (which will try to subscribe)
// Initialize Flic integration (which will just register handlers now, not auto-subscribe)
initFlic();
})
.catch(error => {

306
test.html
View File

@@ -1,36 +1,290 @@
<!DOCTYPE html>
<html lang="en">
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Service Worker Test</title>
<title>Push Notification Debug</title>
<style>
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
button {
padding: 10px;
margin: 5px;
cursor: pointer;
}
pre {
background-color: #f5f5f5;
padding: 10px;
border-radius: 5px;
overflow-x: auto;
}
.section {
margin-bottom: 20px;
padding: 15px;
border: 1px solid #ddd;
border-radius: 5px;
}
</style>
</head>
<body>
<h1>Service Worker Test</h1>
<p>This page tests if the service worker is registered correctly.</p>
<div id="status">Checking service worker registration...</div>
<script>
const statusDiv = document.getElementById('status');
<h1>Push Notification Debug</h1>
<div class="section">
<h2>LocalStorage Management</h2>
<button id="checkCreds">Check Stored Credentials</button>
<button id="clearCreds">Clear Stored Credentials</button>
<pre id="credsOutput"></pre>
</div>
<div class="section">
<h2>Push Subscription Status</h2>
<button id="checkSub">Check Current Subscription</button>
<button id="unsubscribe">Unsubscribe from Push</button>
<pre id="subOutput"></pre>
</div>
<div class="section">
<h2>Manually Trigger Subscription</h2>
<p>Use these buttons to manually trigger the subscription process:</p>
<button id="setupPush">Setup Push Notifications</button>
<button id="forceCredentials">Force New Credentials Prompt</button>
<pre id="setupOutput"></pre>
</div>
<div class="section">
<h2>Test Server Communication</h2>
<p>Send existing subscription to server (tests authentication):</p>
<input type="text" id="buttonId" placeholder="Button ID (leave empty for default)" style="padding: 8px; width: 250px; margin-bottom: 10px;">
<button id="sendToServer">Send Current Subscription to Server</button>
<pre id="serverOutput"></pre>
</div>
<script type="module">
import { setupPushNotifications, forceCredentialsPrompt } from './src/js/services/serviceWorkerManager.js';
import { FLIC_BUTTON_ID } from './src/js/config.js';
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
statusDiv.innerHTML = 'Service worker registered successfully!<br>' +
'Scope: ' + registration.scope;
console.log('ServiceWorker registration successful with scope: ', registration.scope);
})
.catch(error => {
statusDiv.innerHTML = 'Service worker registration failed: ' + error;
console.error('ServiceWorker registration failed: ', error);
// We need direct access to the sendSubscriptionToServer function
// We'll recreate a simplified version here since it's not exported
async function sendSubscriptionToServer(subscription, buttonId) {
const serverOutput = document.getElementById('serverOutput');
serverOutput.textContent = `Sending subscription for button "${buttonId}" to server...`;
try {
// Get stored credentials
const storedAuth = localStorage.getItem('basicAuthCredentials');
let credentials = null;
if (storedAuth) {
try {
credentials = JSON.parse(storedAuth);
if (!credentials.username || !credentials.password) {
throw new Error('Invalid stored credentials');
}
serverOutput.textContent += '\nUsing stored credentials.';
} catch (error) {
serverOutput.textContent += '\nFailed to parse stored credentials.';
}
}
// If no credentials, prompt user
if (!credentials) {
serverOutput.textContent += '\nNo valid credentials found, prompting user...';
const confirmAuth = confirm('Authentication required. Provide credentials now?');
if (!confirmAuth) {
serverOutput.textContent += '\nUser declined to provide credentials.';
return;
}
const username = prompt('Please enter your username:');
if (!username) {
serverOutput.textContent += '\nUsername input cancelled.';
return;
}
const password = prompt('Please enter your password:');
if (!password) {
serverOutput.textContent += '\nPassword input cancelled.';
return;
}
credentials = { username, password };
localStorage.setItem('basicAuthCredentials', JSON.stringify(credentials));
serverOutput.textContent += '\nNew credentials saved.';
}
// Create auth header
const createBasicAuthHeader = (creds) => {
return 'Basic ' + btoa(`${creds.username}:${creds.password}`);
};
// Prepare request
const headers = { 'Content-Type': 'application/json' };
const authHeader = createBasicAuthHeader(credentials);
if (authHeader) headers['Authorization'] = authHeader;
// Get backend URL from config or use a default
let backendUrl;
try {
const configModule = await import('./src/js/config.js');
backendUrl = configModule.BACKEND_URL;
} catch (error) {
backendUrl = prompt('Enter backend URL:', 'https://your-backend-url.com');
if (!backendUrl) return;
}
serverOutput.textContent += `\nSending to: ${backendUrl}/subscribe`;
// Send request
const response = await fetch(`${backendUrl}/subscribe`, {
method: 'POST',
body: JSON.stringify({ button_id: buttonId, subscription: subscription }),
headers: headers,
credentials: 'include'
});
navigator.serviceWorker.ready.then(registration => {
statusDiv.innerHTML += '<br><br>Service worker is ready!';
});
} else {
statusDiv.innerHTML = 'Service workers are not supported in this browser.';
if (response.ok) {
const result = await response.json();
serverOutput.textContent += `\nSuccess! Server response: ${result.message || JSON.stringify(result)}`;
} else {
let errorMsg = `Server error: ${response.status}`;
if (response.status === 401 || response.status === 403) {
localStorage.removeItem('basicAuthCredentials');
errorMsg = 'Authentication failed. Credentials cleared.';
} else {
try {
const errorData = await response.json();
errorMsg = errorData.message || errorMsg;
} catch (e) { /* use default */ }
}
serverOutput.textContent += `\nError: ${errorMsg}`;
}
} catch (error) {
serverOutput.textContent += `\nNetwork error: ${error.message}`;
}
}
// Check credentials
document.getElementById('checkCreds').addEventListener('click', function() {
const creds = localStorage.getItem('basicAuthCredentials');
document.getElementById('credsOutput').textContent =
creds ? `Found: ${creds}` : 'No credentials stored.';
});
// Clear credentials
document.getElementById('clearCreds').addEventListener('click', function() {
localStorage.removeItem('basicAuthCredentials');
document.getElementById('credsOutput').textContent = 'Credentials cleared!';
});
// Check subscription
document.getElementById('checkSub').addEventListener('click', async function() {
const output = document.getElementById('subOutput');
try {
if (!('serviceWorker' in navigator) || !('PushManager' in window)) {
output.textContent = 'Push notifications not supported in this browser.';
return;
}
const registration = await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.getSubscription();
if (subscription) {
output.textContent = 'Active subscription found:\n' +
JSON.stringify(subscription, null, 2);
} else {
output.textContent = 'No active push subscription found.';
}
} catch (error) {
output.textContent = 'Error: ' + error.message;
}
});
// Unsubscribe
document.getElementById('unsubscribe').addEventListener('click', async function() {
const output = document.getElementById('subOutput');
try {
if (!('serviceWorker' in navigator) || !('PushManager' in window)) {
output.textContent = 'Push notifications not supported in this browser.';
return;
}
const registration = await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.getSubscription();
if (subscription) {
await subscription.unsubscribe();
output.textContent = 'Successfully unsubscribed!';
} else {
output.textContent = 'No active subscription to unsubscribe from.';
}
} catch (error) {
output.textContent = 'Error unsubscribing: ' + error.message;
}
});
// Setup push notifications
document.getElementById('setupPush').addEventListener('click', function() {
const output = document.getElementById('setupOutput');
output.textContent = 'Triggering push notification setup...';
try {
setupPushNotifications();
output.textContent += '\nSetup process initiated. Check console for details.';
} catch (error) {
output.textContent += `\nError: ${error.message}`;
}
});
// Force credentials prompt
document.getElementById('forceCredentials').addEventListener('click', function() {
const output = document.getElementById('setupOutput');
output.textContent = 'Forcing new credentials prompt...';
try {
forceCredentialsPrompt();
output.textContent += '\nCredentials prompt initiated. Check console for details.';
} catch (error) {
output.textContent += `\nError: ${error.message}`;
}
});
// Send subscription to server
document.getElementById('sendToServer').addEventListener('click', async function() {
const output = document.getElementById('serverOutput');
try {
if (!('serviceWorker' in navigator) || !('PushManager' in window)) {
output.textContent = 'Push notifications not supported in this browser.';
return;
}
// Get current subscription
const registration = await navigator.serviceWorker.ready;
const subscription = await registration.pushManager.getSubscription();
if (!subscription) {
output.textContent = 'No active subscription found. Please subscribe first.';
return;
}
// Get button ID (use input or default)
let buttonId = document.getElementById('buttonId').value.trim();
if (!buttonId) {
try {
// Try to get from config
buttonId = FLIC_BUTTON_ID;
} catch (e) {
buttonId = 'default-button';
}
}
// Send to server
await sendSubscriptionToServer(subscription, buttonId);
} catch (error) {
output.textContent = `Error: ${error.message}`;
}
});
</script>
</body>
</html>