Files
securebit-chat/test-bluetooth.js

456 lines
16 KiB
JavaScript
Raw Normal View History

2025-10-13 11:13:11 -04:00
// src/components/ui/BluetoothKeyTransfer.jsx
var BluetoothKeyTransfer = ({
webrtcManager,
onKeyReceived,
onStatusChange,
onAutoConnection,
isVisible = false,
onClose
}) => {
const [bluetoothManager, setBluetoothManager] = React.useState(null);
const [isSupported, setIsSupported] = React.useState(false);
const [isAvailable, setIsAvailable] = React.useState(false);
const [isScanning, setIsScanning] = React.useState(false);
const [isAdvertising, setIsAdvertising] = React.useState(false);
const [connectedDevices, setConnectedDevices] = React.useState([]);
const [status, setStatus] = React.useState("idle");
const [error, setError] = React.useState(null);
const [logs, setLogs] = React.useState([]);
React.useEffect(() => {
if (isVisible && !bluetoothManager) {
initializeBluetooth();
}
}, [isVisible]);
React.useEffect(() => {
return () => {
if (bluetoothManager) {
bluetoothManager.cleanup();
}
};
}, [bluetoothManager]);
const initializeBluetooth = async () => {
try {
const manager = new window.BluetoothKeyTransfer(
webrtcManager,
handleStatusChange,
handleKeyReceived,
handleError,
handleAutoConnection
);
setBluetoothManager(manager);
setTimeout(() => {
setIsSupported(manager.isSupported);
setIsAvailable(manager.isAvailable);
}, 100);
} catch (error2) {
console.error("Failed to initialize Bluetooth manager:", error2);
setError("Failed to initialize Bluetooth: " + error2.message);
}
};
const handleStatusChange = (statusType, data) => {
setStatus(statusType);
addLog(`Status: ${statusType}`, data);
switch (statusType) {
case "bluetooth_ready":
setIsSupported(data.supported);
setIsAvailable(data.available);
break;
case "scanning_active":
setIsScanning(true);
break;
case "scanning_stopped":
setIsScanning(false);
break;
case "advertising_active":
setIsAdvertising(true);
break;
case "advertising_stopped":
setIsAdvertising(false);
break;
case "connected":
setConnectedDevices((prev) => [...prev, {
id: data.deviceId,
name: data.deviceName,
connected: true
}]);
break;
}
onStatusChange?.(statusType, data);
};
const handleKeyReceived = (keyData, deviceId) => {
addLog("Key received from device", { deviceId });
onKeyReceived?.(keyData, deviceId);
};
const handleError = (error2) => {
console.error("Bluetooth error:", error2);
setError(error2.message);
addLog("Error", error2.message);
};
const handleAutoConnection = (connectionData) => {
console.log("Auto connection completed:", connectionData);
addLog("Auto Connection Completed", connectionData);
onAutoConnection?.(connectionData);
};
const addLog = (message, data = null) => {
const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString();
const logEntry = {
timestamp,
message,
data: data ? JSON.stringify(data, null, 2) : null
};
setLogs((prev) => [...prev.slice(-9), logEntry]);
};
const startScanning = async () => {
try {
setError(null);
await bluetoothManager.startScanning();
} catch (error2) {
setError("Failed to start scanning: " + error2.message);
}
};
const stopScanning = async () => {
try {
await bluetoothManager.stopScanning();
} catch (error2) {
setError("Failed to stop scanning: " + error2.message);
}
};
const startAdvertising = async () => {
try {
setError(null);
if (!webrtcManager || !webrtcManager.ecdhKeyPair) {
throw new Error("No public key available for advertising");
}
await bluetoothManager.startAdvertising(
webrtcManager.ecdhKeyPair.publicKey,
"SecureBit Device"
);
} catch (error2) {
setError("Failed to start advertising: " + error2.message);
}
};
const stopAdvertising = async () => {
try {
await bluetoothManager.stopAdvertising();
} catch (error2) {
setError("Failed to stop advertising: " + error2.message);
}
};
const sendPublicKey = async (deviceId) => {
try {
setError(null);
if (!webrtcManager || !webrtcManager.ecdhKeyPair) {
throw new Error("No public key available for sending");
}
await bluetoothManager.sendPublicKey(
webrtcManager.ecdhKeyPair.publicKey,
deviceId
);
} catch (error2) {
setError("Failed to send public key: " + error2.message);
}
};
const clearLogs = () => {
setLogs([]);
};
const startAutoConnection = async (deviceId) => {
try {
setError(null);
await bluetoothManager.startAutoConnection(deviceId);
} catch (error2) {
setError("Failed to start auto connection: " + error2.message);
}
};
const startAutoConnectionAsResponder = async (deviceId) => {
try {
setError(null);
await bluetoothManager.startAutoConnectionAsResponder(deviceId);
} catch (error2) {
setError("Failed to start auto connection as responder: " + error2.message);
}
};
if (!isVisible) return null;
return React.createElement("div", {
className: "fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"
}, [
React.createElement("div", {
key: "modal",
className: "bg-gray-900 rounded-lg shadow-xl max-w-2xl w-full max-h-[90vh] overflow-hidden"
}, [
// Header
React.createElement("div", {
key: "header",
className: "flex items-center justify-between p-6 border-b border-gray-700"
}, [
React.createElement("div", {
key: "title",
className: "flex items-center space-x-3"
}, [
React.createElement("i", {
key: "icon",
className: "fas fa-bluetooth text-blue-400 text-xl"
}),
React.createElement("h2", {
key: "text",
className: "text-xl font-semibold text-white"
}, "Bluetooth Key Transfer")
]),
React.createElement("button", {
key: "close",
onClick: onClose,
className: "text-gray-400 hover:text-white transition-colors"
}, [
React.createElement("i", {
className: "fas fa-times text-xl"
})
])
]),
// Content
React.createElement("div", {
key: "content",
className: "p-6 space-y-6 overflow-y-auto max-h-[calc(90vh-200px)]"
}, [
// Status Section
React.createElement("div", {
key: "status",
className: "space-y-4"
}, [
React.createElement("h3", {
key: "title",
className: "text-lg font-medium text-white"
}, "Bluetooth Status"),
React.createElement("div", {
key: "indicators",
className: "grid grid-cols-2 gap-4"
}, [
React.createElement("div", {
key: "support",
className: "flex items-center space-x-2"
}, [
React.createElement("div", {
className: `w-3 h-3 rounded-full ${isSupported ? "bg-green-500" : "bg-red-500"}`
}),
React.createElement("span", {
className: "text-sm text-gray-300"
}, "Bluetooth Supported")
]),
React.createElement("div", {
key: "availability",
className: "flex items-center space-x-2"
}, [
React.createElement("div", {
className: `w-3 h-3 rounded-full ${isAvailable ? "bg-green-500" : "bg-red-500"}`
}),
React.createElement("span", {
className: "text-sm text-gray-300"
}, "Bluetooth Available")
])
])
]),
// Controls Section
React.createElement("div", {
key: "controls",
className: "space-y-4"
}, [
React.createElement("h3", {
key: "title",
className: "text-lg font-medium text-white"
}, "Key Exchange"),
React.createElement("div", {
key: "buttons",
className: "grid grid-cols-1 sm:grid-cols-2 gap-4"
}, [
// Scanning Controls
React.createElement("div", {
key: "scanning",
className: "space-y-2"
}, [
React.createElement("h4", {
key: "title",
className: "text-sm font-medium text-gray-300"
}, "Discover Devices"),
React.createElement("button", {
key: "scan",
onClick: isScanning ? stopScanning : startScanning,
disabled: !isSupported || !isAvailable,
className: `w-full px-4 py-2 rounded-lg font-medium transition-colors ${isScanning ? "bg-red-600 hover:bg-red-700 text-white" : "bg-blue-600 hover:bg-blue-700 text-white disabled:bg-gray-600 disabled:cursor-not-allowed"}`
}, [
React.createElement("i", {
key: "icon",
className: `fas ${isScanning ? "fa-stop" : "fa-search"} mr-2`
}),
isScanning ? "Stop Scanning" : "Start Scanning"
])
]),
// Advertising Controls
React.createElement("div", {
key: "advertising",
className: "space-y-2"
}, [
React.createElement("h4", {
key: "title",
className: "text-sm font-medium text-gray-300"
}, "Share Your Key"),
React.createElement("button", {
key: "advertise",
onClick: isAdvertising ? stopAdvertising : startAdvertising,
disabled: !isSupported || !isAvailable,
className: `w-full px-4 py-2 rounded-lg font-medium transition-colors ${isAdvertising ? "bg-red-600 hover:bg-red-700 text-white" : "bg-green-600 hover:bg-green-700 text-white disabled:bg-gray-600 disabled:cursor-not-allowed"}`
}, [
React.createElement("i", {
key: "icon",
className: `fas ${isAdvertising ? "fa-stop" : "fa-broadcast-tower"} mr-2`
}),
isAdvertising ? "Stop Sharing" : "Start Sharing"
])
])
])
]),
// Connected Devices
connectedDevices.length > 0 && React.createElement("div", {
key: "devices",
className: "space-y-4"
}, [
React.createElement("h3", {
key: "title",
className: "text-lg font-medium text-white"
}, "Connected Devices"),
React.createElement("div", {
key: "list",
className: "space-y-2"
}, connectedDevices.map(
(device) => React.createElement("div", {
key: device.id,
className: "flex items-center justify-between p-3 bg-gray-800 rounded-lg"
}, [
React.createElement("div", {
key: "info",
className: "flex items-center space-x-3"
}, [
React.createElement("i", {
key: "icon",
className: "fas fa-mobile-alt text-blue-400"
}),
React.createElement("span", {
key: "name",
className: "text-white"
}, device.name)
]),
React.createElement("div", {
key: "buttons",
className: "flex space-x-2"
}, [
React.createElement("button", {
key: "auto-connect",
onClick: () => startAutoConnection(device.id),
className: "px-3 py-1 bg-green-600 hover:bg-green-700 text-white text-sm rounded transition-colors"
}, "Auto Connect"),
React.createElement("button", {
key: "auto-respond",
onClick: () => startAutoConnectionAsResponder(device.id),
className: "px-3 py-1 bg-purple-600 hover:bg-purple-700 text-white text-sm rounded transition-colors"
}, "Auto Respond"),
React.createElement("button", {
key: "send",
onClick: () => sendPublicKey(device.id),
className: "px-3 py-1 bg-blue-600 hover:bg-blue-700 text-white text-sm rounded transition-colors"
}, "Send Key")
])
])
))
]),
// Error Display
error && React.createElement("div", {
key: "error",
className: "p-4 bg-red-900 border border-red-700 rounded-lg"
}, [
React.createElement("div", {
key: "header",
className: "flex items-center space-x-2 mb-2"
}, [
React.createElement("i", {
key: "icon",
className: "fas fa-exclamation-triangle text-red-400"
}),
React.createElement("h4", {
key: "title",
className: "text-red-400 font-medium"
}, "Error")
]),
React.createElement("p", {
key: "message",
className: "text-red-300 text-sm"
}, error)
]),
// Logs Section
React.createElement("div", {
key: "logs",
className: "space-y-4"
}, [
React.createElement("div", {
key: "header",
className: "flex items-center justify-between"
}, [
React.createElement("h3", {
key: "title",
className: "text-lg font-medium text-white"
}, "Activity Log"),
React.createElement("button", {
key: "clear",
onClick: clearLogs,
className: "text-sm text-gray-400 hover:text-white transition-colors"
}, "Clear")
]),
React.createElement(
"div",
{
key: "log-list",
className: "bg-gray-800 rounded-lg p-4 max-h-40 overflow-y-auto"
},
logs.length === 0 ? React.createElement("p", {
key: "empty",
className: "text-gray-400 text-sm text-center"
}, "No activity yet") : logs.map(
(log, index) => React.createElement("div", {
key: index,
className: "text-xs text-gray-300 mb-1"
}, [
React.createElement("span", {
key: "time",
className: "text-gray-500"
}, `[${log.timestamp}] `),
React.createElement("span", {
key: "message",
className: "text-gray-300"
}, log.message),
log.data && React.createElement("pre", {
key: "data",
className: "text-gray-400 mt-1 ml-4"
}, log.data)
])
)
)
])
]),
// Footer
React.createElement("div", {
key: "footer",
className: "flex items-center justify-between p-6 border-t border-gray-700"
}, [
React.createElement("div", {
key: "info",
className: "text-sm text-gray-400"
}, "Bluetooth key exchange provides secure device-to-device communication"),
React.createElement("button", {
key: "close-footer",
onClick: onClose,
className: "px-4 py-2 bg-gray-700 hover:bg-gray-600 text-white rounded-lg transition-colors"
}, "Close")
])
])
]);
};
if (typeof window !== "undefined") {
window.BluetoothKeyTransfer = BluetoothKeyTransfer;
}