WebApp Guard & Manifest Architect

Security Headers Generator

PWA Manifest Architect

Standard icon declarations will be generated. Uploading custom icons requires a paid plan.

Basic service worker hint included. Advanced strategies require a paid plan.

Free use limit reached. Unlock unlimited access.

You've used all 3 free generations. Subscribe or make a one-time purchase to continue without limits, get advanced features, and direct downloads.

Single App Access

Unlock WebApp Guard & Manifest Architect forever.

Crypto Micro-payment

Pay securely with Solana or Bitcoin.

Sign In

Don't have an account? Sign Up

Pay with Crypto

Scan the QR code below to complete your payment.

Crypto Payment QR Code

Amount:

Address:

Currency:

Waiting for payment...

/* const CACHE_NAME = 'pwa-cache-v1'; const urlsToCache = [ '/', '/index.html', '/styles.css', // Or your main CSS file '/script.js', // Or your main JS file '/icons/icon-192x192.png' // Example icon ]; self.addEventListener('install', event => { event.waitUntil( caches.open(CACHE_NAME) .then(cache => { console.log('Opened cache'); return cache.addAll(urlsToCache); }) ); }); self.addEventListener('fetch', event => { event.respondWith( caches.match(event.request) .then(response => { if (response) { return response; } return fetch(event.request); }) ); }); */ `; getElementById('pwaManifestOutput').value += "\n\n" + swHint; }; // --- Payment & Auth Logic --- let isUnlocked = localStorage.getItem(`pv_unlocked_${WIDGET_SLUG}`) === 'true'; let actionCount = parseInt(localStorage.getItem(`pv_actions_${WIDGET_SLUG}`) || '0'); const FREE_ACTION_LIMIT = 3; const showLoading = (show) => { getElementById('loading-spinner').style.display = show ? 'flex' : 'none'; }; const toggleOverlay = (show) => { getElementById('payment-overlay').classList.toggle('active', show); }; const toggleLoginModal = (show) => { getElementById('login-modal').classList.toggle('active', show); if (show) { getElementById('auth-email').value = ''; getElementById('auth-password').value = ''; getElementById('auth-error-message').textContent = ''; updateAuthModalUI(); } }; const toggleCryptoModal = (show) => { getElementById('crypto-modal').classList.toggle('active', show); if (!show && pollingIntervalId) { clearInterval(pollingIntervalId); pollingIntervalId = null; } }; const incrementActionCount = () => { if (isUnlocked) return; actionCount++; localStorage.setItem(`pv_actions_${WIDGET_SLUG}`, actionCount); if (actionCount >= FREE_ACTION_LIMIT) { toggleOverlay(true); } }; const unlockWidget = () => { isUnlocked = true; localStorage.setItem(`pv_unlocked_${WIDGET_SLUG}`, 'true'); toggleOverlay(false); toggleLoginModal(false); toggleCryptoModal(false); // Re-enable any disabled elements that were locked document.querySelectorAll('.premium-action-trigger').forEach(btn => btn.disabled = false); // Visually indicate unlimited access? (Optional) }; const checkSubscriptionStatus = async (userEmail) => { if (!userEmail) return false; try { const response = await fetch(`${API_BASE_URL}/check-subscription?email=${encodeURIComponent(userEmail)}`); const data = await response.json(); return data.active; } catch (error) { console.error("Error checking subscription:", error); return false; } }; // Firebase Auth State Listener auth.onAuthStateChanged(async (user) => { if (user) { getElementById('hub-subscribe-btn').textContent = translations[currentLang].hubSubscribeBtnAuth; const isActiveSubscription = await checkSubscriptionStatus(user.email); if (isActiveSubscription) { unlockWidget(); } } else { getElementById('hub-subscribe-btn').textContent = translations[currentLang].hubSubscribeBtnAnon; // If not logged in and not explicitly unlocked, re-apply limits if needed. if (!isUnlocked && actionCount >= FREE_ACTION_LIMIT) { toggleOverlay(true); } } }); const handleStripeVerification = async () => { const urlParams = new URLSearchParams(window.location.search); const sessionId = urlParams.get('session_id'); const status = urlParams.get('status'); const subscriptionStatus = urlParams.get('subscription_status'); if (sessionId && (status === 'success' || subscriptionStatus === 'success')) { showLoading(true); try { const verifyUrl = status === 'success' ? `${API_BASE_URL}/verify-session?session_id=${sessionId}` : `${API_BASE_URL}/check-subscription?email=${encodeURIComponent(auth.currentUser?.email || 'N/A')}`; const response = await fetch(verifyUrl); const data = await response.json(); if (data.active || data.status === 'paid' || data.subscriptionActive) { unlockWidget(); alert("Payment successful! You now have unlimited access."); } else { alert("Payment verification failed. Please contact support."); } } catch (error) { console.error("Stripe verification error:", error); alert("An error occurred during payment verification. Please contact support."); } finally { showLoading(false); // Clear URL parameters history.replaceState({}, document.title, window.location.pathname); } } }; // Initial checks on load document.addEventListener('DOMContentLoaded', async () => { updateContent(); if (isUnlocked) { // If already unlocked from localStorage, bypass all checks document.querySelectorAll('.premium-action-trigger').forEach(btn => btn.disabled = false); } else { // Check Stripe success callback in URL first await handleStripeVerification(); } // Bind event listeners for actions getElementById('generateSecurityHeadersBtn').addEventListener('click', () => { incrementActionCount(); if (!isUnlocked && actionCount > FREE_ACTION_LIMIT) return; // Prevent action if locked generateSecurityHeaders(); }); getElementById('generatePWAManifestBtn').addEventListener('click', () => { incrementActionCount(); if (!isUnlocked && actionCount > FREE_ACTION_LIMIT) return; // Prevent action if locked generatePWAManifest(); }); getElementById('downloadManifestBtn').addEventListener('click', () => { incrementActionCount(); if (!isUnlocked && actionCount > FREE_ACTION_LIMIT) return; // Prevent action if locked const manifestContent = getElementById('pwaManifestOutput').value; const pwaName = getElementById('pwa-name').value || translations[currentLang].pwaNamePlaceholder; const message = translations[currentLang].whatsappDownloadMessage || `Hello, I'd like to download my PWA manifest and security headers from WebApp Guard & Manifest Architect. Here are my generated details:\n\nApp Name: ${pwaName}\n\nManifest:\n${manifestContent}`; const whatsappUrl = `https://wa.me/${WHATSAPP_NUMBER}?text=${encodeURIComponent(message)}`; window.open(whatsappUrl, '_blank'); }); // Payment buttons getElementById('hub-subscribe-btn').addEventListener('click', async () => { if (!auth.currentUser) { toggleLoginModal(true); } else { showLoading(true); try { const response = await fetch(`${API_BASE_URL}/create-hub-subscription`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ email: auth.currentUser.email, userId: auth.currentUser.uid }) }); const data = await response.json(); if (data.url) { window.location.href = data.url; } else { alert('Failed to create subscription checkout. Please try again.'); } } catch (error) { console.error('Error creating Hub subscription:', error); alert('An error occurred. Please try again.'); } finally { showLoading(false); } } }); getElementById('single-app-pay-btn').addEventListener('click', async () => { showLoading(true); try { const response = await fetch(`${API_BASE_URL}/create-session`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ slug: WIDGET_SLUG, amount: 199, // $1.99 widgetName: "WebApp Guard & Manifest Architect" }) }); const data = await response.json(); if (data.url) { window.location.href = data.url; } else { alert('Failed to create checkout session. Please try again.'); } } catch (error) { console.error('Error creating Stripe session:', error); alert('An error occurred. Please try again.'); } finally { showLoading(false); } }); getElementById('crypto-pay-btn').addEventListener('click', async () => { toggleOverlay(false); // Hide main overlay toggleCryptoModal(true); // Show crypto modal showLoading(true); try { const response = await fetch(`${API_BASE_URL}/request-crypto`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ slug: WIDGET_SLUG, amount: 199, widgetName: "WebApp Guard & Manifest Architect" }) }); const data = await response.json(); if (data.qrCodeUrl && data.amount && data.address && data.currency && data.paymentId) { getElementById('crypto-qr-code').src = data.qrCodeUrl; getElementById('crypto-modal-amount').textContent = `${(data.amount / 100).toFixed(2)} USD`; getElementById('crypto-modal-address').textContent = data.address; getElementById('crypto-modal-currency').textContent = data.currency; getElementById('crypto-modal-status').textContent = translations[currentLang].cryptoModalStatusWaiting; startCryptoPaymentPolling(data.paymentId); } else { alert('Failed to generate crypto payment. Please try again.'); toggleCryptoModal(false); toggleOverlay(true); } } catch (error) { console.error('Error requesting crypto payment:', error); alert('An error occurred during crypto payment request. Please try again.'); toggleCryptoModal(false); toggleOverlay(true); } finally { showLoading(false); } }); // Login modal event listeners getElementById('close-login-modal').addEventListener('click', () => toggleLoginModal(false)); getElementById('toggle-auth-mode').addEventListener('click', (e) => { e.preventDefault(); isAuthModeLogin = !isAuthModeLogin; updateAuthModalUI(); }); getElementById('auth-submit-btn').addEventListener('click', async () => { const email = getElementById('auth-email').value; const password = getElementById('auth-password').value; const errorMessageElement = getElementById('auth-error-message'); errorMessageElement.textContent = ''; // Clear previous errors if (!email || !password) { errorMessageElement.textContent = 'Email and password cannot be empty.'; return; } showLoading(true); try { if (isAuthModeLogin) { await auth.signInWithEmailAndPassword(email, password); } else { await auth.createUserWithEmailAndPassword(email, password); } toggleLoginModal(false); // Close login modal on success toggleOverlay(false); // Close main overlay, auth state listener will handle unlock } catch (error) { console.error("Auth error:", error); errorMessageElement.textContent = translations[currentLang].authErrorMessage; } finally { showLoading(false); } }); getElementById('google-signin-btn').addEventListener('click', async () => { showLoading(true); try { const provider = new firebase.auth.GoogleAuthProvider(); await auth.signInWithPopup(provider); toggleLoginModal(false); toggleOverlay(false); // auth state listener will handle unlock } catch (error) { console.error("Google Sign-In error:", error); getElementById('auth-error-message').textContent = translations[currentLang].authErrorMessage; } finally { showLoading(false); } }); getElementById('close-crypto-modal').addEventListener('click', () => { toggleCryptoModal(false); if (!isUnlocked) toggleOverlay(true); // Re-show main overlay if not unlocked }); // Initially check if locked if (!isUnlocked && actionCount >= FREE_ACTION_LIMIT) { toggleOverlay(true); } }); const updateAuthModalUI = () => { const t = translations[currentLang]; getElementById('login-modal-title').textContent = isAuthModeLogin ? t.loginModalTitle : t.toggleAuthLinkLogin; getElementById('auth-submit-btn').textContent = isAuthModeLogin ? t.loginModalSubmitLogin : t.loginModalSubmitRegister; getElementById('toggle-auth-text').textContent = isAuthModeLogin ? t.toggleAuthTextLogin : t.toggleAuthTextRegister; getElementById('toggle-auth-mode').textContent = isAuthModeLogin ? t.toggleAuthLinkLogin : t.toggleAuthLinkRegister; getElementById('auth-error-message').textContent = ''; }; const startCryptoPaymentPolling = (paymentId) => { const pollCryptoStatus = async () => { try { const response = await fetch(`${API_BASE_URL}/verify-crypto?paymentId=${paymentId}`); const data = await response.json(); if (data.status === 'paid') { getElementById('crypto-modal-status').textContent = translations[currentLang].cryptoModalStatusPaid; clearInterval(pollingIntervalId); unlockWidget(); alert(translations[currentLang].cryptoModalStatusPaid); toggleCryptoModal(false); } else if (data.status === 'failed' || data.status === 'expired') { getElementById('crypto-modal-status').textContent = translations[currentLang].cryptoModalStatusError; clearInterval(pollingIntervalId); } } catch (error) { console.error("Error polling crypto payment:", error); getElementById('crypto-modal-status').textContent = translations[currentLang].cryptoModalStatusError; clearInterval(pollingIntervalId); } }; pollingIntervalId = setInterval(pollCryptoStatus, 5000); // Poll every 5 seconds };