Deploy: 2026-05-21 19:07:54
This commit is contained in:
@@ -82,7 +82,7 @@ class Response
|
|||||||
$this->json($response, $code);
|
$this->json($response, $code);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function sendHeaders(): void
|
public function sendHeaders(): void
|
||||||
{
|
{
|
||||||
if (headers_sent()) {
|
if (headers_sent()) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class SecurityMiddleware
|
|||||||
$response->setHeader('X-XSS-Protection', '1; mode=block'); // Prevent Cross-Site Scripting (XSS)
|
$response->setHeader('X-XSS-Protection', '1; mode=block'); // Prevent Cross-Site Scripting (XSS)
|
||||||
$response->setHeader('X-Content-Type-Options', 'nosniff'); // Prevent MIME-sniffing
|
$response->setHeader('X-Content-Type-Options', 'nosniff'); // Prevent MIME-sniffing
|
||||||
$response->setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload'); // HSTS
|
$response->setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload'); // HSTS
|
||||||
$response->setHeader('Content-Security-Policy', "default-src 'self'; script-src 'self'; object-src 'none';"); // CSP
|
$response->setHeader('Content-Security-Policy', "default-src 'self'; script-src 'self' 'unsafe-eval' https://unpkg.com https://cdnjs.cloudflare.com; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; object-src 'none';"); // CSP
|
||||||
|
|
||||||
// 2. Input Sanitization to prevent XSS (Recursive)
|
// 2. Input Sanitization to prevent XSS (Recursive)
|
||||||
$body = $request->getBody();
|
$body = $request->getBody();
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Outfit:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Outfit:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||||
<!-- QR Code Generator Library -->
|
<!-- QR Code Generator Library -->
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js" integrity="sha512-CNgIRecGo7nOMxObXtLZHyYy34UNrJDzFGaPZ55S56sxM57SL7gOhv4/dIncsaYRiLJHdU8mHgGybkx9thStTA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js" integrity="sha512-CNgIRecGo7nphbeZ04Sc13ka07paqdeTu0WR1IM4kNcpmBAUSHSQX0FslNhTDadL4O5SAGapGt4FodqL8My0mA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||||
<!-- AlpineJS CDN -->
|
<!-- AlpineJS CDN -->
|
||||||
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
|
||||||
|
|
||||||
@@ -725,6 +725,19 @@
|
|||||||
<div id="qrcode-canvas" x-init="$nextTick(() => renderQr())"></div>
|
<div id="qrcode-canvas" x-init="$nextTick(() => renderQr())"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Diagnostics -->
|
||||||
|
<div style="font-size: 0.75rem; margin: 0.5rem 0; display: flex; flex-direction: column; gap: 0.25rem;">
|
||||||
|
<template x-if="!whatsappSession.qr_code">
|
||||||
|
<span style="color: var(--danger-accent);">⚠️ Decryption issue: QR code string is empty.</span>
|
||||||
|
</template>
|
||||||
|
<template x-if="whatsappSession.qr_code">
|
||||||
|
<span style="color: var(--success-accent);">✓ Encrypted QR data retrieved successfully.</span>
|
||||||
|
</template>
|
||||||
|
<template x-if="typeof window.QRCode === 'undefined'">
|
||||||
|
<span style="color: var(--danger-accent);">⚠️ QRCode library failed to load (Integrity/CSP issue).</span>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style="font-size: 0.8rem; display: flex; align-items: center; justify-content: center; gap: 0.5rem;" class="text-muted">
|
<div style="font-size: 0.8rem; display: flex; align-items: center; justify-content: center; gap: 0.5rem;" class="text-muted">
|
||||||
<div class="spinner" style="width: 14px; height: 14px; border-width: 2px;"></div>
|
<div class="spinner" style="width: 14px; height: 14px; border-width: 2px;"></div>
|
||||||
<span>Waiting for connection handshake...</span>
|
<span>Waiting for connection handshake...</span>
|
||||||
@@ -1056,18 +1069,29 @@
|
|||||||
|
|
||||||
renderQr() {
|
renderQr() {
|
||||||
const canvasDiv = document.getElementById('qrcode-canvas');
|
const canvasDiv = document.getElementById('qrcode-canvas');
|
||||||
if (!canvasDiv || !this.whatsappSession || !this.whatsappSession.qr_code) return;
|
console.log('renderQr() invoked. canvasDiv:', canvasDiv, 'Session data:', this.whatsappSession);
|
||||||
|
if (!canvasDiv || !this.whatsappSession || !this.whatsappSession.qr_code) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Clear previous QR instance
|
try {
|
||||||
canvasDiv.innerHTML = '';
|
if (typeof window.QRCode === 'undefined') {
|
||||||
new QRCode(canvasDiv, {
|
throw new Error('QRCode class is not defined. Script resource failed to load.');
|
||||||
text: this.whatsappSession.qr_code,
|
}
|
||||||
width: 200,
|
// Clear previous QR instance
|
||||||
height: 200,
|
canvasDiv.innerHTML = '';
|
||||||
colorDark: "#0b0d19",
|
new QRCode(canvasDiv, {
|
||||||
colorLight: "#ffffff",
|
text: this.whatsappSession.qr_code,
|
||||||
correctLevel: QRCode.CorrectLevel.H
|
width: 200,
|
||||||
});
|
height: 200,
|
||||||
|
colorDark: "#0b0d19",
|
||||||
|
colorLight: "#ffffff",
|
||||||
|
correctLevel: QRCode.CorrectLevel.H
|
||||||
|
});
|
||||||
|
console.log('QR Code generated successfully.');
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Error generating QR code:', e);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
startPolling() {
|
startPolling() {
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ $router->use(\App\Middlewares\SecurityMiddleware::class);
|
|||||||
// 4. Define API Routes
|
// 4. Define API Routes
|
||||||
// Serve index.html dashboard on root path
|
// Serve index.html dashboard on root path
|
||||||
$router->get('/', function ($request, $response) {
|
$router->get('/', function ($request, $response) {
|
||||||
header('Content-Type: text/html; charset=utf-8');
|
$response->setHeader('Content-Type', 'text/html; charset=utf-8');
|
||||||
|
$response->sendHeaders();
|
||||||
readfile(__DIR__ . '/index.html');
|
readfile(__DIR__ . '/index.html');
|
||||||
exit;
|
exit;
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user