diff --git a/docker-compose.yml b/docker-compose.yml
index 9e1f78b..a2df860 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -171,7 +171,6 @@ services:
- "8082:8080"
environment:
- FG_PUBLIC_PATH=/files-ui
- platform: linux/amd64
networks:
cell-network:
diff --git a/webui/package.json b/webui/package.json
index 39dcb79..1c9d530 100644
--- a/webui/package.json
+++ b/webui/package.json
@@ -18,7 +18,8 @@
"clsx": "^2.0.0",
"tailwindcss": "^3.4.0",
"autoprefixer": "^10.4.16",
- "postcss": "^8.4.32"
+ "postcss": "^8.4.32",
+ "qrcode": "^1.5.3"
},
"devDependencies": {
"@eslint/js": "^9.30.1",
diff --git a/webui/src/pages/Peers.jsx b/webui/src/pages/Peers.jsx
index 231d920..c05dc2a 100644
--- a/webui/src/pages/Peers.jsx
+++ b/webui/src/pages/Peers.jsx
@@ -1,6 +1,7 @@
import { useState, useEffect } from 'react';
-import { Plus, Trash2, Edit, Eye, Wifi, Shield, Copy, Download, Key, Smartphone, QrCode } from 'lucide-react';
+import { Plus, Trash2, Edit, Eye, Wifi, Shield, Copy, Download, Key, Smartphone } from 'lucide-react';
import { peerAPI, wireguardAPI } from '../services/api';
+import QRCode from 'qrcode';
function Peers() {
const [peers, setPeers] = useState([]);
@@ -27,22 +28,6 @@ function Peers() {
useEffect(() => {
fetchPeers();
-
- // Test QR code library loading
- const testQR = () => {
- console.log('Testing QR code library...');
- console.log('QRCode available:', typeof QRCode);
- console.log('window.QRCode available:', typeof window.QRCode);
-
- if (typeof QRCode !== 'undefined') {
- console.log('✅ QRCode library loaded successfully');
- } else {
- console.log('❌ QRCode library not loaded, will use fallback');
- }
- };
-
- // Test after a short delay to allow library to load
- setTimeout(testQR, 1000);
}, []);
const fetchPeers = async () => {
@@ -172,19 +157,29 @@ function Peers() {
const getServerConfig = async () => {
try {
// Try to get server configuration from API
+ console.log('Fetching server config from:', '/api/wireguard/server-config');
const response = await fetch('/api/wireguard/server-config');
+ console.log('Server config response status:', response.status);
+ console.log('Server config response ok:', response.ok);
+
if (response.ok) {
const config = await response.json();
+ console.log('Server config from API:', config);
return {
public_key: config.public_key || "SERVER_PUBLIC_KEY_PLACEHOLDER",
endpoint: config.endpoint || "YOUR_SERVER_IP:51820"
};
+ } else {
+ console.error('Failed to get server config, status:', response.status);
+ const errorText = await response.text();
+ console.error('Error response:', errorText);
}
} catch (error) {
console.warn('Could not get server config:', error);
}
// Return default values
+ console.log('Using fallback server config');
return {
public_key: "SERVER_PUBLIC_KEY_PLACEHOLDER",
endpoint: "YOUR_SERVER_IP:51820"
@@ -210,7 +205,9 @@ function Peers() {
setSelectedPeer(peer);
try {
// Get server configuration first
+ console.log('Getting server config for peer:', peer.name);
const serverConfig = await getServerConfig();
+ console.log('Server config received:', serverConfig);
// Create peer with server config
const peerWithServerConfig = {
@@ -218,6 +215,7 @@ function Peers() {
server_public_key: serverConfig.public_key,
server_endpoint: serverConfig.endpoint
};
+ console.log('Peer with server config:', peerWithServerConfig);
// Try to get existing config first
const response = await wireguardAPI.getPeerConfig({ name: peer.name });
@@ -232,10 +230,12 @@ function Peers() {
// Generate QR code for the config using QR-specific format
try {
- const qrConfig = generateQRConfig(peerWithServerConfig);
- console.log('QR Config for peer:', peer.name);
- console.log('QR Config content:', qrConfig);
- const qrDataUrl = await generateQRCode(qrConfig);
+ console.log('Generating QR config for peer:', peer.name);
+ console.log('Using config from API for QR code:', config);
+
+ // Use the same config string that works for the text area
+ // It already has the correct server data from the API
+ const qrDataUrl = await generateQRCode(config);
setQrCodeDataUrl(qrDataUrl);
} catch (qrError) {
console.error('Failed to generate QR code:', qrError);
@@ -315,176 +315,24 @@ AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25`;
};
- const generateQRCode = (text) => {
- return new Promise((resolve, reject) => {
- const tryGenerate = (attempts = 0) => {
- try {
- // Check if QRCode library is available
- if (typeof QRCode !== 'undefined') {
- console.log('Using QRCode library for QR generation');
- QRCode.toDataURL(text, {
- width: 256,
- margin: 2,
- color: {
- dark: '#000000',
- light: '#FFFFFF'
- },
- errorCorrectionLevel: 'M'
- }, (err, url) => {
- if (err) {
- console.error('QR Code generation error:', err);
- reject(err);
- } else {
- console.log('QR Code generated successfully');
- resolve(url);
- }
- });
- } else if (typeof qrcode !== 'undefined') {
- console.log('Using qrcode-generator library for QR generation');
- try {
- const qr = qrcode(0, 'M');
- qr.addData(text);
- qr.make();
-
- const canvas = document.createElement('canvas');
- const ctx = canvas.getContext('2d');
- const size = 256;
- const moduleCount = qr.getModuleCount();
- const cellSize = Math.floor(size / moduleCount);
-
- canvas.width = size;
- canvas.height = size;
-
- // Fill with white background
- ctx.fillStyle = '#FFFFFF';
- ctx.fillRect(0, 0, size, size);
-
- // Draw QR code
- ctx.fillStyle = '#000000';
- for (let row = 0; row < moduleCount; row++) {
- for (let col = 0; col < moduleCount; col++) {
- if (qr.isDark(row, col)) {
- ctx.fillRect(col * cellSize, row * cellSize, cellSize, cellSize);
- }
- }
- }
-
- console.log('QR Code generated with qrcode-generator');
- resolve(canvas.toDataURL());
- } catch (qrError) {
- console.error('qrcode-generator error:', qrError);
- const fallbackQR = generateFallbackQR(text);
- resolve(fallbackQR);
- }
- } else if (attempts < 10) {
- // Wait a bit for the library to load
- console.log(`QR libraries not loaded yet, attempt ${attempts + 1}/10`);
- setTimeout(() => tryGenerate(attempts + 1), 100);
- } else {
- // Fallback after 10 attempts
- console.warn('QR libraries failed to load, using fallback');
- const fallbackQR = generateFallbackQR(text);
- resolve(fallbackQR);
- }
- } catch (error) {
- console.error('QR Code generation error:', error);
- reject(error);
- }
- };
-
- tryGenerate();
- });
+ const generateQRCode = async (text) => {
+ try {
+ const qrDataUrl = await QRCode.toDataURL(text, {
+ width: 256,
+ margin: 2,
+ color: {
+ dark: '#000000',
+ light: '#FFFFFF'
+ },
+ errorCorrectionLevel: 'M'
+ });
+ return qrDataUrl;
+ } catch (error) {
+ console.error('QR Code generation error:', error);
+ throw error;
+ }
};
- const generateFallbackQR = (text) => {
- // Create a simple but functional QR code using a basic algorithm
- const canvas = document.createElement('canvas');
- const ctx = canvas.getContext('2d');
- const size = 256;
-
- canvas.width = size;
- canvas.height = size;
-
- // Fill with white background
- ctx.fillStyle = '#FFFFFF';
- ctx.fillRect(0, 0, size, size);
-
- // Create a simple QR code structure
- const moduleSize = 4;
- const modules = Math.floor(size / moduleSize);
-
- // Simple LFSR-based pattern generator for more realistic QR appearance
- let lfsr = text.split('').reduce((acc, char) => acc ^ char.charCodeAt(0), 0xACE1);
-
- // Generate data pattern
- for (let x = 0; x < modules; x++) {
- for (let y = 0; y < modules; y++) {
- // Skip corner marker areas
- const isCorner = (x < 7 && y < 7) || (x >= modules - 7 && y < 7) || (x < 7 && y >= modules - 7);
- if (isCorner) continue;
-
- // Skip timing pattern areas
- const isTiming = (x === 6) || (y === 6);
- if (isTiming) continue;
-
- // Generate pseudo-random bit using LFSR
- lfsr = (lfsr >> 1) ^ (-(lfsr & 1) & 0xB400);
- const shouldFill = (lfsr & 1) === 1;
-
- if (shouldFill) {
- ctx.fillStyle = '#000000';
- ctx.fillRect(x * moduleSize, y * moduleSize, moduleSize, moduleSize);
- }
- }
- }
-
- // Add corner markers (7x7 modules)
- const markerSize = 7;
- const markerModules = markerSize * moduleSize;
-
- // Top-left corner marker
- ctx.fillStyle = '#000000';
- ctx.fillRect(0, 0, markerModules, markerModules);
- ctx.fillStyle = '#FFFFFF';
- ctx.fillRect(moduleSize, moduleSize, 5 * moduleSize, 5 * moduleSize);
- ctx.fillStyle = '#000000';
- ctx.fillRect(2 * moduleSize, 2 * moduleSize, 3 * moduleSize, 3 * moduleSize);
-
- // Top-right corner marker
- ctx.fillStyle = '#000000';
- ctx.fillRect(size - markerModules, 0, markerModules, markerModules);
- ctx.fillStyle = '#FFFFFF';
- ctx.fillRect(size - 6 * moduleSize, moduleSize, 5 * moduleSize, 5 * moduleSize);
- ctx.fillStyle = '#000000';
- ctx.fillRect(size - 5 * moduleSize, 2 * moduleSize, 3 * moduleSize, 3 * moduleSize);
-
- // Bottom-left corner marker
- ctx.fillStyle = '#000000';
- ctx.fillRect(0, size - markerModules, markerModules, markerModules);
- ctx.fillStyle = '#FFFFFF';
- ctx.fillRect(moduleSize, size - 6 * moduleSize, 5 * moduleSize, 5 * moduleSize);
- ctx.fillStyle = '#000000';
- ctx.fillRect(2 * moduleSize, size - 5 * moduleSize, 3 * moduleSize, 3 * moduleSize);
-
- // Add timing patterns (alternating black/white modules)
- ctx.fillStyle = '#000000';
- for (let i = 8; i < modules - 8; i += 2) {
- ctx.fillRect(6 * moduleSize, i * moduleSize, moduleSize, moduleSize);
- ctx.fillRect(i * moduleSize, 6 * moduleSize, moduleSize, moduleSize);
- }
-
- // Add a simple data area pattern that looks more realistic
- ctx.fillStyle = '#000000';
- for (let x = 8; x < modules - 8; x++) {
- for (let y = 8; y < modules - 8; y++) {
- if ((x + y) % 3 === 0) {
- ctx.fillRect(x * moduleSize, y * moduleSize, moduleSize, moduleSize);
- }
- }
- }
-
- return canvas.toDataURL();
- };
const handleEditPeer = (peer) => {
setSelectedPeer(peer);
@@ -669,7 +517,9 @@ PersistentKeepalive = 25`;
className="text-green-600 hover:text-green-900"
title="Show QR Code"
>
-