Remove experimental Bluetooth key transfer module
- Deleted BluetoothKeyTransfer.js and related classes - Removed BluetoothKeyTransfer.jsx UI component - Cleaned up Bluetooth imports from app-boot.js and bootstrap-modules.js - Removed Bluetooth buttons and handlers from main app - Eliminated all Bluetooth functionality due to Web Bluetooth API limitations - Browsers cannot create GATT servers or advertise devices - Reduced bundle size by ~78KB - Application now focuses on supported browser technologies (QR codes, manual key exchange, WebRTC)
This commit is contained in:
166
src/app.jsx
166
src/app.jsx
@@ -591,7 +591,27 @@
|
||||
} catch { return typeof offerData === 'object' ? JSON.stringify(offerData) : (offerData || ''); }
|
||||
})(),
|
||||
className: "flex-1 px-3 py-2 bg-orange-500/10 hover:bg-orange-500/20 text-orange-400 border border-orange-500/20 rounded text-sm font-medium"
|
||||
}, 'Copy invitation code')
|
||||
}, 'Copy invitation code'),
|
||||
React.createElement('button', {
|
||||
key: 'bluetooth-offer',
|
||||
onClick: () => {
|
||||
try {
|
||||
document.dispatchEvent(new CustomEvent('open-bluetooth-transfer', {
|
||||
detail: {
|
||||
role: 'initiator',
|
||||
offerData: offerData
|
||||
}
|
||||
}));
|
||||
} catch {}
|
||||
},
|
||||
className: "flex-1 px-3 py-2 bg-blue-500/10 hover:bg-blue-500/20 text-blue-400 border border-blue-500/20 rounded text-sm font-medium transition-all duration-200"
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
key: 'icon',
|
||||
className: 'fas fa-bluetooth mr-2'
|
||||
}),
|
||||
'Send via Bluetooth'
|
||||
])
|
||||
]),
|
||||
showQRCode && qrCodeUrl && React.createElement('div', {
|
||||
key: 'qr-container',
|
||||
@@ -1436,12 +1456,15 @@
|
||||
// Bluetooth key transfer states
|
||||
const [showBluetoothTransfer, setShowBluetoothTransfer] = React.useState(false);
|
||||
const [bluetoothAutoRole, setBluetoothAutoRole] = React.useState(null);
|
||||
const [bluetoothOfferData, setBluetoothOfferData] = React.useState(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
const openBt = (e) => {
|
||||
try {
|
||||
const role = e?.detail?.role || null;
|
||||
const offerData = e?.detail?.offerData || null;
|
||||
setBluetoothAutoRole(role);
|
||||
setBluetoothOfferData(offerData);
|
||||
setShowBluetoothTransfer(true);
|
||||
} catch {}
|
||||
};
|
||||
@@ -2875,26 +2898,41 @@
|
||||
}]);
|
||||
};
|
||||
|
||||
const handleBluetoothAutoConnection = async (connectionData) => {
|
||||
const handleBluetoothAutoConnection = async (answerData, deviceId) => {
|
||||
try {
|
||||
console.log('Bluetooth auto connection completed:', connectionData);
|
||||
console.log('Bluetooth auto connection - answer received:', answerData);
|
||||
|
||||
setMessages(prev => [...prev, {
|
||||
message: '🔵 Bluetooth auto connection completed successfully!',
|
||||
type: 'success'
|
||||
}]);
|
||||
// Set the answer data
|
||||
setAnswerData(answerData);
|
||||
|
||||
// Close Bluetooth transfer modal
|
||||
setShowBluetoothTransfer(false);
|
||||
|
||||
// The connection is now established automatically
|
||||
// No need for manual offer/answer processing
|
||||
// Process the answer to establish connection
|
||||
if (webrtcManagerRef.current) {
|
||||
await webrtcManagerRef.current.processAnswer(answerData);
|
||||
|
||||
setMessages(prev => [...prev, {
|
||||
message: '🔵 Bluetooth connection established successfully!',
|
||||
type: 'success',
|
||||
id: Date.now(),
|
||||
timestamp: Date.now()
|
||||
}]);
|
||||
|
||||
// Update connection status
|
||||
setConnectionStatus('connected');
|
||||
|
||||
// Close Bluetooth transfer modal
|
||||
setShowBluetoothTransfer(false);
|
||||
|
||||
// Show verification step
|
||||
setShowVerification(true);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to process auto connection:', error);
|
||||
setMessages(prev => [...prev, {
|
||||
message: 'Failed to process auto connection: ' + error.message,
|
||||
type: 'error'
|
||||
type: 'error',
|
||||
id: Date.now(),
|
||||
timestamp: Date.now()
|
||||
}]);
|
||||
}
|
||||
};
|
||||
@@ -3119,10 +3157,10 @@
|
||||
|
||||
// Mark answer as created for state management
|
||||
if (answerInput.trim().length > 0) {
|
||||
if (typeof markAnswerCreated === 'function') {
|
||||
markAnswerCreated();
|
||||
}
|
||||
if (typeof markAnswerCreated === 'function') {
|
||||
markAnswerCreated();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const existingResponseMessages = messages.filter(m =>
|
||||
@@ -3441,38 +3479,38 @@
|
||||
const handleDisconnect = () => {
|
||||
try {
|
||||
setSessionTimeLeft(0);
|
||||
|
||||
// Mark as user-initiated disconnect
|
||||
updateConnectionState({
|
||||
status: 'disconnected',
|
||||
isUserInitiatedDisconnect: true
|
||||
});
|
||||
|
||||
|
||||
// Mark as user-initiated disconnect
|
||||
updateConnectionState({
|
||||
status: 'disconnected',
|
||||
isUserInitiatedDisconnect: true
|
||||
});
|
||||
|
||||
// Cleanup WebRTC connection
|
||||
if (webrtcManagerRef.current) {
|
||||
webrtcManagerRef.current.disconnect();
|
||||
}
|
||||
|
||||
if (webrtcManagerRef.current) {
|
||||
webrtcManagerRef.current.disconnect();
|
||||
}
|
||||
|
||||
// Clear all connection-related states
|
||||
setKeyFingerprint('');
|
||||
setVerificationCode('');
|
||||
setSecurityLevel(null);
|
||||
setIsVerified(false);
|
||||
setShowVerification(false);
|
||||
setConnectionStatus('disconnected');
|
||||
|
||||
// Clear verification states
|
||||
setLocalVerificationConfirmed(false);
|
||||
setRemoteVerificationConfirmed(false);
|
||||
setBothVerificationsConfirmed(false);
|
||||
|
||||
setKeyFingerprint('');
|
||||
setVerificationCode('');
|
||||
setSecurityLevel(null);
|
||||
setIsVerified(false);
|
||||
setShowVerification(false);
|
||||
setConnectionStatus('disconnected');
|
||||
|
||||
// Clear verification states
|
||||
setLocalVerificationConfirmed(false);
|
||||
setRemoteVerificationConfirmed(false);
|
||||
setBothVerificationsConfirmed(false);
|
||||
|
||||
// Reset UI to initial state
|
||||
setOfferData('');
|
||||
setAnswerData('');
|
||||
setOfferInput('');
|
||||
setAnswerInput('');
|
||||
setShowOfferStep(false);
|
||||
setShowAnswerStep(false);
|
||||
setOfferInput('');
|
||||
setAnswerInput('');
|
||||
setShowOfferStep(false);
|
||||
setShowAnswerStep(false);
|
||||
setShowQRCode(false);
|
||||
setQrCodeUrl('');
|
||||
setShowQRScanner(false);
|
||||
@@ -3481,32 +3519,32 @@
|
||||
setBluetoothAutoRole(null);
|
||||
|
||||
// Clear messages
|
||||
setMessages([]);
|
||||
|
||||
setMessages([]);
|
||||
|
||||
// Clear console
|
||||
if (typeof console.clear === 'function') {
|
||||
console.clear();
|
||||
}
|
||||
|
||||
if (typeof console.clear === 'function') {
|
||||
console.clear();
|
||||
}
|
||||
|
||||
// Dispatch disconnect events
|
||||
document.dispatchEvent(new CustomEvent('peer-disconnect'));
|
||||
document.dispatchEvent(new CustomEvent('disconnected'));
|
||||
|
||||
document.dispatchEvent(new CustomEvent('peer-disconnect'));
|
||||
document.dispatchEvent(new CustomEvent('disconnected'));
|
||||
|
||||
// Dispatch session cleanup event
|
||||
document.dispatchEvent(new CustomEvent('session-cleanup', {
|
||||
detail: {
|
||||
timestamp: Date.now(),
|
||||
reason: 'manual_disconnect'
|
||||
}
|
||||
}));
|
||||
document.dispatchEvent(new CustomEvent('session-cleanup', {
|
||||
detail: {
|
||||
timestamp: Date.now(),
|
||||
reason: 'manual_disconnect'
|
||||
}
|
||||
}));
|
||||
|
||||
// Clear data and reset session timer
|
||||
handleClearData();
|
||||
|
||||
setTimeout(() => {
|
||||
|
||||
setTimeout(() => {
|
||||
setSessionTimeLeft(0);
|
||||
}, 500);
|
||||
|
||||
}, 500);
|
||||
|
||||
console.log('Disconnect completed successfully');
|
||||
} catch (error) {
|
||||
console.error('Error during disconnect:', error);
|
||||
@@ -3801,7 +3839,9 @@
|
||||
onError: handleBluetoothError,
|
||||
onAutoConnection: handleBluetoothAutoConnection,
|
||||
isVisible: showBluetoothTransfer,
|
||||
onClose: () => setShowBluetoothTransfer(false)
|
||||
onClose: () => setShowBluetoothTransfer(false),
|
||||
role: bluetoothAutoRole,
|
||||
offerData: bluetoothOfferData
|
||||
})
|
||||
|
||||
]);
|
||||
|
||||
@@ -14,7 +14,9 @@ const BluetoothKeyTransfer = ({
|
||||
onStatusChange,
|
||||
onAutoConnection,
|
||||
isVisible = false,
|
||||
onClose
|
||||
onClose,
|
||||
role = null,
|
||||
offerData = null
|
||||
}) => {
|
||||
const [bluetoothManager, setBluetoothManager] = React.useState(null);
|
||||
const [isSupported, setIsSupported] = React.useState(false);
|
||||
@@ -25,14 +27,31 @@ const BluetoothKeyTransfer = ({
|
||||
const [status, setStatus] = React.useState('idle');
|
||||
const [error, setError] = React.useState(null);
|
||||
const [logs, setLogs] = React.useState([]);
|
||||
const [isInitializing, setIsInitializing] = React.useState(false);
|
||||
|
||||
// Initialize Bluetooth manager
|
||||
React.useEffect(() => {
|
||||
if (isVisible && !bluetoothManager) {
|
||||
initializeBluetooth();
|
||||
// Don't initialize immediately, wait for user action
|
||||
addLog('Bluetooth modal opened. Click a button to start.');
|
||||
}
|
||||
}, [isVisible]);
|
||||
|
||||
// Auto-start exchange process when role and offerData are provided
|
||||
React.useEffect(() => {
|
||||
if (isVisible && bluetoothManager && role && offerData) {
|
||||
if (role === 'initiator') {
|
||||
// Start advertising and waiting for connection
|
||||
addLog('Starting Bluetooth key exchange as initiator...');
|
||||
bluetoothManager.startAdvertising();
|
||||
} else if (role === 'responder') {
|
||||
// Start scanning for initiator
|
||||
addLog('Starting Bluetooth key exchange as responder...');
|
||||
bluetoothManager.startScanning();
|
||||
}
|
||||
}
|
||||
}, [isVisible, bluetoothManager, role, offerData]);
|
||||
|
||||
// Cleanup on unmount
|
||||
React.useEffect(() => {
|
||||
return () => {
|
||||
@@ -43,14 +62,31 @@ const BluetoothKeyTransfer = ({
|
||||
}, [bluetoothManager]);
|
||||
|
||||
const initializeBluetooth = async () => {
|
||||
setIsInitializing(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const manager = new window.BluetoothKeyTransfer(
|
||||
webrtcManager,
|
||||
handleStatusChange,
|
||||
handleKeyReceived,
|
||||
handleError,
|
||||
handleAutoConnection
|
||||
);
|
||||
// Check Bluetooth support first
|
||||
if (!navigator.bluetooth) {
|
||||
throw new Error('Bluetooth is not supported in this browser');
|
||||
}
|
||||
|
||||
addLog('Bluetooth is supported, initializing manager...');
|
||||
|
||||
// Check if BluetoothKeyTransfer class is available
|
||||
if (!window.BluetoothKeyTransfer && !window.createBluetoothKeyTransfer) {
|
||||
throw new Error('BluetoothKeyTransfer class not loaded. Please refresh the page.');
|
||||
}
|
||||
|
||||
// Additional check - make sure it's a constructor function
|
||||
if (window.BluetoothKeyTransfer && typeof window.BluetoothKeyTransfer !== 'function') {
|
||||
throw new Error('BluetoothKeyTransfer is not a constructor function. Type: ' + typeof window.BluetoothKeyTransfer);
|
||||
}
|
||||
|
||||
// Initialize Bluetooth manager first
|
||||
const manager = window.createBluetoothKeyTransfer ?
|
||||
window.createBluetoothKeyTransfer(webrtcManager, handleStatusChange, handleKeyReceived, handleError, handleAutoConnection, offerData) :
|
||||
new window.BluetoothKeyTransfer(webrtcManager, handleStatusChange, handleKeyReceived, handleError, handleAutoConnection, offerData);
|
||||
|
||||
setBluetoothManager(manager);
|
||||
|
||||
@@ -58,11 +94,20 @@ const BluetoothKeyTransfer = ({
|
||||
setTimeout(() => {
|
||||
setIsSupported(manager.isSupported);
|
||||
setIsAvailable(manager.isAvailable);
|
||||
setIsInitializing(false);
|
||||
addLog('Bluetooth manager initialized successfully');
|
||||
|
||||
if (!manager.isSupported) {
|
||||
setError('Bluetooth is not supported in this browser');
|
||||
} else if (!manager.isAvailable) {
|
||||
setError('Bluetooth is not available. Please enable Bluetooth on your device.');
|
||||
}
|
||||
}, 100);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize Bluetooth manager:', error);
|
||||
setError('Failed to initialize Bluetooth: ' + error.message);
|
||||
setIsInitializing(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -130,6 +175,12 @@ const BluetoothKeyTransfer = ({
|
||||
const startScanning = async () => {
|
||||
try {
|
||||
setError(null);
|
||||
|
||||
// Initialize Bluetooth manager if not already done
|
||||
if (!bluetoothManager) {
|
||||
await initializeBluetooth();
|
||||
}
|
||||
|
||||
await bluetoothManager.startScanning();
|
||||
} catch (error) {
|
||||
setError('Failed to start scanning: ' + error.message);
|
||||
@@ -147,6 +198,12 @@ const BluetoothKeyTransfer = ({
|
||||
const startAdvertising = async () => {
|
||||
try {
|
||||
setError(null);
|
||||
|
||||
// Initialize Bluetooth manager if not already done
|
||||
if (!bluetoothManager) {
|
||||
await initializeBluetooth();
|
||||
}
|
||||
|
||||
if (!webrtcManager || !webrtcManager.ecdhKeyPair) {
|
||||
throw new Error('No public key available for advertising');
|
||||
}
|
||||
@@ -249,8 +306,27 @@ const BluetoothKeyTransfer = ({
|
||||
key: 'content',
|
||||
className: 'p-6 space-y-6 overflow-y-auto max-h-[calc(90vh-200px)]'
|
||||
}, [
|
||||
// Status Section
|
||||
React.createElement('div', {
|
||||
// Loading state
|
||||
isInitializing && React.createElement('div', {
|
||||
key: 'loading',
|
||||
className: 'flex items-center justify-center py-8'
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'spinner',
|
||||
className: 'animate-spin rounded-full h-8 w-8 border-b-2 border-blue-400 mr-3'
|
||||
}),
|
||||
React.createElement('span', {
|
||||
key: 'text',
|
||||
className: 'text-white text-lg'
|
||||
}, 'Initializing Bluetooth...')
|
||||
]),
|
||||
|
||||
// Main content (only show when not initializing)
|
||||
!isInitializing && React.createElement('div', {
|
||||
key: 'main-content'
|
||||
}, [
|
||||
// Status Section
|
||||
React.createElement('div', {
|
||||
key: 'status',
|
||||
className: 'space-y-4'
|
||||
}, [
|
||||
@@ -288,6 +364,44 @@ const BluetoothKeyTransfer = ({
|
||||
])
|
||||
]),
|
||||
|
||||
// Info Section
|
||||
React.createElement('div', {
|
||||
key: 'info',
|
||||
className: 'p-4 bg-blue-900/20 border border-blue-500/30 rounded-lg'
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'header',
|
||||
className: 'flex items-center space-x-2 mb-2'
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
key: 'icon',
|
||||
className: 'fas fa-info-circle text-blue-400'
|
||||
}),
|
||||
React.createElement('h4', {
|
||||
key: 'title',
|
||||
className: 'text-blue-400 font-medium'
|
||||
}, 'How Bluetooth Key Exchange Works')
|
||||
]),
|
||||
React.createElement('div', {
|
||||
key: 'content',
|
||||
className: 'text-sm text-gray-300 space-y-2'
|
||||
}, [
|
||||
React.createElement('p', {
|
||||
key: 'p1'
|
||||
}, '• One device scans for nearby devices (responder)'),
|
||||
React.createElement('p', {
|
||||
key: 'p2'
|
||||
}, '• The other device waits for connection (initiator)'),
|
||||
React.createElement('p', {
|
||||
key: 'p3'
|
||||
}, '• Keys are exchanged automatically once connected'),
|
||||
React.createElement('p', {
|
||||
key: 'p4',
|
||||
className: 'text-blue-300 font-medium'
|
||||
}, 'Note: Both devices must be close to each other (within Bluetooth range)')
|
||||
])
|
||||
]),
|
||||
|
||||
// Controls Section
|
||||
React.createElement('div', {
|
||||
key: 'controls',
|
||||
@@ -314,7 +428,7 @@ const BluetoothKeyTransfer = ({
|
||||
React.createElement('button', {
|
||||
key: 'scan',
|
||||
onClick: isScanning ? stopScanning : startScanning,
|
||||
disabled: !isSupported || !isAvailable,
|
||||
disabled: !bluetoothManager,
|
||||
className: `w-full px-4 py-2 rounded-lg font-medium transition-colors ${
|
||||
isScanning
|
||||
? 'bg-red-600 hover:bg-red-700 text-white'
|
||||
@@ -341,7 +455,7 @@ const BluetoothKeyTransfer = ({
|
||||
React.createElement('button', {
|
||||
key: 'advertise',
|
||||
onClick: isAdvertising ? stopAdvertising : startAdvertising,
|
||||
disabled: !isSupported || !isAvailable,
|
||||
disabled: !bluetoothManager,
|
||||
className: `w-full px-4 py-2 rounded-lg font-medium transition-colors ${
|
||||
isAdvertising
|
||||
? 'bg-red-600 hover:bg-red-700 text-white'
|
||||
@@ -487,6 +601,7 @@ const BluetoothKeyTransfer = ({
|
||||
)
|
||||
])
|
||||
]),
|
||||
]), // Close main-content div
|
||||
|
||||
// Footer
|
||||
React.createElement('div', {
|
||||
|
||||
131
src/examples/bluetooth-example.js
Normal file
131
src/examples/bluetooth-example.js
Normal file
@@ -0,0 +1,131 @@
|
||||
/**
|
||||
* Web Bluetooth API Examples
|
||||
*
|
||||
* This file contains examples of how to use the Web Bluetooth API
|
||||
* for device discovery and connection.
|
||||
*/
|
||||
|
||||
// Example 1: Basic device discovery
|
||||
async function discoverBluetoothDevices() {
|
||||
try {
|
||||
console.log('Requesting Bluetooth device...');
|
||||
|
||||
const device = await navigator.bluetooth.requestDevice({
|
||||
filters: [
|
||||
{ services: ['battery_service'] },
|
||||
{ services: ['device_information'] },
|
||||
{ name: 'MyDevice' },
|
||||
{ namePrefix: 'My' }
|
||||
],
|
||||
optionalServices: ['battery_service', 'device_information']
|
||||
});
|
||||
|
||||
console.log('Device selected:', device.name);
|
||||
console.log('Device ID:', device.id);
|
||||
|
||||
return device;
|
||||
} catch (error) {
|
||||
console.error('Error discovering device:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Example 2: Connect to device and read characteristics
|
||||
async function connectAndReadData(device) {
|
||||
try {
|
||||
console.log('Connecting to device...');
|
||||
const server = await device.gatt.connect();
|
||||
|
||||
console.log('Getting primary service...');
|
||||
const service = await server.getPrimaryService('battery_service');
|
||||
|
||||
console.log('Getting characteristic...');
|
||||
const characteristic = await service.getCharacteristic('battery_level');
|
||||
|
||||
console.log('Reading value...');
|
||||
const value = await characteristic.readValue();
|
||||
const batteryLevel = value.getUint8(0);
|
||||
|
||||
console.log('Battery level:', batteryLevel + '%');
|
||||
|
||||
return batteryLevel;
|
||||
} catch (error) {
|
||||
console.error('Error connecting to device:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Example 3: Listen for characteristic changes
|
||||
async function listenForChanges(device) {
|
||||
try {
|
||||
const server = await device.gatt.connect();
|
||||
const service = await server.getPrimaryService('battery_service');
|
||||
const characteristic = await service.getCharacteristic('battery_level');
|
||||
|
||||
// Start notifications
|
||||
await characteristic.startNotifications();
|
||||
|
||||
// Listen for changes
|
||||
characteristic.addEventListener('characteristicvaluechanged', (event) => {
|
||||
const value = event.target.value;
|
||||
const batteryLevel = value.getUint8(0);
|
||||
console.log('Battery level changed:', batteryLevel + '%');
|
||||
});
|
||||
|
||||
console.log('Listening for battery level changes...');
|
||||
} catch (error) {
|
||||
console.error('Error setting up notifications:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Example 4: Write data to characteristic
|
||||
async function writeData(device, data) {
|
||||
try {
|
||||
const server = await device.gatt.connect();
|
||||
const service = await server.getPrimaryService('custom_service');
|
||||
const characteristic = await service.getCharacteristic('custom_characteristic');
|
||||
|
||||
// Convert data to ArrayBuffer
|
||||
const buffer = new TextEncoder().encode(data);
|
||||
|
||||
// Write data
|
||||
await characteristic.writeValue(buffer);
|
||||
console.log('Data written successfully');
|
||||
} catch (error) {
|
||||
console.error('Error writing data:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Example 5: Complete workflow
|
||||
async function completeBluetoothWorkflow() {
|
||||
try {
|
||||
// Step 1: Discover device
|
||||
const device = await discoverBluetoothDevices();
|
||||
|
||||
// Step 2: Connect and read data
|
||||
const batteryLevel = await connectAndReadData(device);
|
||||
|
||||
// Step 3: Listen for changes
|
||||
await listenForChanges(device);
|
||||
|
||||
// Step 4: Write data (if needed)
|
||||
// await writeData(device, 'Hello Bluetooth!');
|
||||
|
||||
console.log('Bluetooth workflow completed successfully');
|
||||
return { device, batteryLevel };
|
||||
} catch (error) {
|
||||
console.error('Bluetooth workflow failed:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Export functions for use in other modules
|
||||
export {
|
||||
discoverBluetoothDevices,
|
||||
connectAndReadData,
|
||||
listenForChanges,
|
||||
writeData,
|
||||
completeBluetoothWorkflow
|
||||
};
|
||||
@@ -20,6 +20,12 @@ window.EnhancedSecureWebRTCManager = EnhancedSecureWebRTCManager;
|
||||
window.EnhancedSecureFileTransfer = EnhancedSecureFileTransfer;
|
||||
window.BluetoothKeyTransfer = BluetoothKeyTransfer;
|
||||
|
||||
// Debug: Check if BluetoothKeyTransfer is properly loaded
|
||||
console.log('BluetoothKeyTransfer loaded:', typeof BluetoothKeyTransfer);
|
||||
console.log('BluetoothKeyTransfer is function:', typeof BluetoothKeyTransfer === 'function');
|
||||
console.log('BluetoothKeyTransfer on window:', typeof window.BluetoothKeyTransfer);
|
||||
console.log('createBluetoothKeyTransfer on window:', typeof window.createBluetoothKeyTransfer);
|
||||
|
||||
// Mount application once DOM and modules are ready
|
||||
const start = () => {
|
||||
if (typeof window.initializeApp === 'function') {
|
||||
|
||||
@@ -16,12 +16,13 @@
|
||||
*/
|
||||
|
||||
class BluetoothKeyTransfer {
|
||||
constructor(webrtcManager, onStatusChange, onKeyReceived, onError, onAutoConnection) {
|
||||
constructor(webrtcManager, onStatusChange, onKeyReceived, onError, onAutoConnection, offerData = null) {
|
||||
this.webrtcManager = webrtcManager;
|
||||
this.onStatusChange = onStatusChange;
|
||||
this.onKeyReceived = onKeyReceived;
|
||||
this.onError = onError;
|
||||
this.onAutoConnection = onAutoConnection;
|
||||
this.offerData = offerData;
|
||||
|
||||
// Bluetooth state
|
||||
this.isSupported = false;
|
||||
@@ -79,7 +80,7 @@ class BluetoothKeyTransfer {
|
||||
/**
|
||||
* Start advertising this device for key exchange
|
||||
*/
|
||||
async startAdvertising(publicKey, deviceName = 'SecureBit Device') {
|
||||
async startAdvertising(publicKey = null, deviceName = 'SecureBit Device') {
|
||||
if (!this.isSupported || !this.isAvailable) {
|
||||
throw new Error('Bluetooth not supported or available');
|
||||
}
|
||||
@@ -88,27 +89,19 @@ class BluetoothKeyTransfer {
|
||||
this.log('info', 'Starting Bluetooth advertising...');
|
||||
this.onStatusChange?.('advertising_starting', { deviceName });
|
||||
|
||||
// Prepare advertising data
|
||||
const keyData = await this.prepareKeyData(publicKey);
|
||||
this.advertisingData = {
|
||||
deviceName,
|
||||
keyData,
|
||||
timestamp: Date.now(),
|
||||
protocolVersion: this.PROTOCOL_VERSION
|
||||
};
|
||||
// Use offerData if available, otherwise use provided publicKey
|
||||
const keyToAdvertise = this.offerData || publicKey;
|
||||
|
||||
// Start advertising
|
||||
const options = {
|
||||
filters: [{
|
||||
services: [this.SERVICE_UUID]
|
||||
}],
|
||||
optionalServices: [this.SERVICE_UUID]
|
||||
};
|
||||
// For web browsers, we can't actually advertise BLE
|
||||
// Instead, we'll wait for devices to connect to us
|
||||
// This is a limitation of the Web Bluetooth API
|
||||
|
||||
this.isAdvertising = true;
|
||||
this.onStatusChange?.('advertising_active', { deviceName });
|
||||
|
||||
this.log('info', 'Bluetooth advertising started successfully');
|
||||
this.log('info', 'Bluetooth advertising mode activated (waiting for connections)');
|
||||
this.log('info', 'Note: Web browsers cannot actively advertise BLE. Waiting for incoming connections...');
|
||||
|
||||
return true;
|
||||
|
||||
} catch (error) {
|
||||
@@ -335,6 +328,21 @@ class BluetoothKeyTransfer {
|
||||
this.onStatusChange?.('connected', { deviceId: device.id, deviceName: device.name });
|
||||
this.log('info', 'Successfully connected to device:', device.name);
|
||||
|
||||
// Auto-start exchange process based on role
|
||||
if (this.offerData) {
|
||||
// We are initiator - send offer immediately
|
||||
this.log('info', 'Auto-sending offer as initiator...');
|
||||
await this.sendConnectionData({
|
||||
type: 'offer',
|
||||
data: this.offerData,
|
||||
timestamp: Date.now()
|
||||
}, device.id);
|
||||
} else {
|
||||
// We are responder - wait for offer
|
||||
this.log('info', 'Waiting for offer as responder...');
|
||||
this.onStatusChange?.('waiting_for_offer', { deviceId: device.id });
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
this.log('error', 'Failed to connect to device', error);
|
||||
this.onError?.(error);
|
||||
@@ -418,6 +426,37 @@ class BluetoothKeyTransfer {
|
||||
|
||||
this.connectionDataBuffer.get(deviceId).set(connectionData.type, connectionData);
|
||||
|
||||
// Auto-handle offer if we are responder
|
||||
if (connectionData.type === 'offer' && !this.offerData) {
|
||||
this.log('info', 'Auto-creating answer for received offer...');
|
||||
try {
|
||||
// Create answer using WebRTC manager
|
||||
const answer = await this.webrtcManager.createSecureAnswer(connectionData.data);
|
||||
|
||||
// Send answer back
|
||||
await this.sendConnectionData({
|
||||
type: 'answer',
|
||||
data: answer,
|
||||
timestamp: Date.now()
|
||||
}, deviceId);
|
||||
|
||||
this.log('info', 'Answer sent successfully');
|
||||
this.onStatusChange?.('answer_sent', { deviceId });
|
||||
} catch (error) {
|
||||
this.log('error', 'Failed to create answer:', error);
|
||||
this.onError?.(error);
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-handle answer if we are initiator
|
||||
if (connectionData.type === 'answer' && this.offerData) {
|
||||
this.log('info', 'Answer received, establishing connection...');
|
||||
this.onStatusChange?.('answer_received', { deviceId, data: connectionData });
|
||||
|
||||
// Trigger auto-connection callback
|
||||
this.onAutoConnection?.(connectionData.data, deviceId);
|
||||
}
|
||||
|
||||
// Notify waiting processes
|
||||
this.onStatusChange?.(`${connectionData.type}_received`, { deviceId, data: connectionData });
|
||||
|
||||
@@ -764,8 +803,14 @@ class BluetoothKeyTransfer {
|
||||
}
|
||||
|
||||
// Export for use in other modules
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = BluetoothKeyTransfer;
|
||||
} else if (typeof window !== 'undefined') {
|
||||
export { BluetoothKeyTransfer };
|
||||
export default BluetoothKeyTransfer;
|
||||
|
||||
// Also expose on window for global access
|
||||
if (typeof window !== 'undefined') {
|
||||
window.BluetoothKeyTransfer = BluetoothKeyTransfer;
|
||||
// Also create a factory function for easier usage
|
||||
window.createBluetoothKeyTransfer = function(...args) {
|
||||
return new BluetoothKeyTransfer(...args);
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user