feat: implement automatic key generation on channel creation
- Remove manual "Create secure keys" button requirement - Add automatic key generation trigger when "Create channel" is clicked - Implement loading state with spinner animation during key generation - Add isGeneratingKeys state management across components - Pass handleCreateOffer function as prop to EnhancedConnectionSetup - Update UI to show "Generating secure keys..." message during process - Ensure proper state cleanup on disconnect and data clearing - Improve user experience by eliminating extra click step in channel creation flow
This commit is contained in:
43
dist/app.js
vendored
43
dist/app.js
vendored
@@ -268,12 +268,15 @@ var EnhancedConnectionSetup = ({
|
|||||||
nextQrFrame,
|
nextQrFrame,
|
||||||
prevQrFrame,
|
prevQrFrame,
|
||||||
markAnswerCreated,
|
markAnswerCreated,
|
||||||
notificationIntegrationRef
|
notificationIntegrationRef,
|
||||||
|
isGeneratingKeys,
|
||||||
|
handleCreateOffer
|
||||||
}) => {
|
}) => {
|
||||||
const [mode, setMode] = React.useState("select");
|
const [mode, setMode] = React.useState("select");
|
||||||
const [notificationPermissionRequested, setNotificationPermissionRequested] = React.useState(false);
|
const [notificationPermissionRequested, setNotificationPermissionRequested] = React.useState(false);
|
||||||
const resetToSelect = () => {
|
const resetToSelect = () => {
|
||||||
setMode("select");
|
setMode("select");
|
||||||
|
setIsGeneratingKeys(false);
|
||||||
onClearData();
|
onClearData();
|
||||||
};
|
};
|
||||||
const handleVerificationConfirm = () => {
|
const handleVerificationConfirm = () => {
|
||||||
@@ -293,8 +296,8 @@ var EnhancedConnectionSetup = ({
|
|||||||
if (!window.isSecureContext && window.location.protocol !== "https:" && window.location.hostname !== "localhost") {
|
if (!window.isSecureContext && window.location.protocol !== "https:" && window.location.hostname !== "localhost") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const currentPermission = typeof Notification !== "undefined" && Notification ? Notification.permission : "denied";
|
const currentPermission = Notification.permission;
|
||||||
if (typeof Notification !== "undefined" && currentPermission === "default") {
|
if (currentPermission === "default") {
|
||||||
const permission = await Notification.requestPermission();
|
const permission = await Notification.requestPermission();
|
||||||
if (permission === "granted") {
|
if (permission === "granted") {
|
||||||
try {
|
try {
|
||||||
@@ -307,7 +310,6 @@ var EnhancedConnectionSetup = ({
|
|||||||
}
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
try {
|
try {
|
||||||
if (typeof Notification === "undefined") return;
|
|
||||||
const welcomeNotification = new Notification("SecureBit Chat", {
|
const welcomeNotification = new Notification("SecureBit Chat", {
|
||||||
body: "Notifications enabled! You will receive alerts for new messages.",
|
body: "Notifications enabled! You will receive alerts for new messages.",
|
||||||
icon: "/logo/icon-192x192.png",
|
icon: "/logo/icon-192x192.png",
|
||||||
@@ -323,7 +325,7 @@ var EnhancedConnectionSetup = ({
|
|||||||
}
|
}
|
||||||
}, 1e3);
|
}, 1e3);
|
||||||
}
|
}
|
||||||
} else if (typeof Notification !== "undefined" && currentPermission === "granted") {
|
} else if (currentPermission === "granted") {
|
||||||
try {
|
try {
|
||||||
if (window.NotificationIntegration && webrtcManagerRef.current && !notificationIntegrationRef.current) {
|
if (window.NotificationIntegration && webrtcManagerRef.current && !notificationIntegrationRef.current) {
|
||||||
const integration = new window.NotificationIntegration(webrtcManagerRef.current);
|
const integration = new window.NotificationIntegration(webrtcManagerRef.current);
|
||||||
@@ -334,7 +336,6 @@ var EnhancedConnectionSetup = ({
|
|||||||
}
|
}
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
try {
|
try {
|
||||||
if (typeof Notification === "undefined") return;
|
|
||||||
const testNotification = new Notification("SecureBit Chat", {
|
const testNotification = new Notification("SecureBit Chat", {
|
||||||
body: "Notifications are working! You will receive alerts for new messages.",
|
body: "Notifications are working! You will receive alerts for new messages.",
|
||||||
icon: "/logo/icon-192x192.png",
|
icon: "/logo/icon-192x192.png",
|
||||||
@@ -404,6 +405,11 @@ var EnhancedConnectionSetup = ({
|
|||||||
onClick: () => {
|
onClick: () => {
|
||||||
requestNotificationPermissionOnInteraction();
|
requestNotificationPermissionOnInteraction();
|
||||||
setMode("create");
|
setMode("create");
|
||||||
|
setTimeout(() => {
|
||||||
|
if (webrtcManagerRef.current) {
|
||||||
|
handleCreateOffer();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
},
|
},
|
||||||
className: "card-minimal rounded-xl p-6 cursor-pointer group flex-1 create"
|
className: "card-minimal rounded-xl p-6 cursor-pointer group flex-1 create"
|
||||||
}, [
|
}, [
|
||||||
@@ -590,16 +596,15 @@ var EnhancedConnectionSetup = ({
|
|||||||
key: "description",
|
key: "description",
|
||||||
className: "text-secondary text-sm mb-4"
|
className: "text-secondary text-sm mb-4"
|
||||||
}, "Creating cryptographically strong keys and codes to protect against attacks"),
|
}, "Creating cryptographically strong keys and codes to protect against attacks"),
|
||||||
!showOfferStep && React.createElement("button", {
|
!showOfferStep && isGeneratingKeys && React.createElement("div", {
|
||||||
key: "create-btn",
|
key: "loading-state",
|
||||||
onClick: onCreateOffer,
|
className: "w-full py-3 px-4 rounded-lg font-medium transition-all duration-200 bg-blue-500/10 border border-blue-500/20 text-blue-400 flex items-center justify-center"
|
||||||
disabled: connectionStatus === "connecting",
|
|
||||||
className: `w-full btn-primary text-white py-3 px-4 rounded-lg font-medium transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed`
|
|
||||||
}, [
|
}, [
|
||||||
React.createElement("i", {
|
React.createElement("i", {
|
||||||
className: "fas fa-shield-alt mr-2"
|
key: "spinner",
|
||||||
|
className: "fas fa-spinner fa-spin mr-2"
|
||||||
}),
|
}),
|
||||||
"Create secure keys"
|
"Generating secure keys..."
|
||||||
]),
|
]),
|
||||||
showOfferStep && React.createElement("div", {
|
showOfferStep && React.createElement("div", {
|
||||||
key: "offer-result",
|
key: "offer-result",
|
||||||
@@ -1360,6 +1365,7 @@ var EnhancedSecureP2PChat = () => {
|
|||||||
const [qrCodeUrl, setQrCodeUrl] = React.useState("");
|
const [qrCodeUrl, setQrCodeUrl] = React.useState("");
|
||||||
const [showQRScanner, setShowQRScanner] = React.useState(false);
|
const [showQRScanner, setShowQRScanner] = React.useState(false);
|
||||||
const [showQRScannerModal, setShowQRScannerModal] = React.useState(false);
|
const [showQRScannerModal, setShowQRScannerModal] = React.useState(false);
|
||||||
|
const [isGeneratingKeys, setIsGeneratingKeys2] = React.useState(false);
|
||||||
const [isVerified, setIsVerified] = React.useState(false);
|
const [isVerified, setIsVerified] = React.useState(false);
|
||||||
const [securityLevel, setSecurityLevel] = React.useState(null);
|
const [securityLevel, setSecurityLevel] = React.useState(null);
|
||||||
const [sessionTimeLeft, setSessionTimeLeft] = React.useState(0);
|
const [sessionTimeLeft, setSessionTimeLeft] = React.useState(0);
|
||||||
@@ -1672,7 +1678,7 @@ var EnhancedSecureP2PChat = () => {
|
|||||||
handleAnswerError,
|
handleAnswerError,
|
||||||
handleVerificationStateChange
|
handleVerificationStateChange
|
||||||
);
|
);
|
||||||
if (typeof Notification !== "undefined" && Notification.permission === "granted" && window.NotificationIntegration && !notificationIntegrationRef.current) {
|
if (Notification.permission === "granted" && window.NotificationIntegration && !notificationIntegrationRef.current) {
|
||||||
try {
|
try {
|
||||||
const integration = new window.NotificationIntegration(webrtcManagerRef2.current);
|
const integration = new window.NotificationIntegration(webrtcManagerRef2.current);
|
||||||
integration.init().then(() => {
|
integration.init().then(() => {
|
||||||
@@ -2449,6 +2455,7 @@ var EnhancedSecureP2PChat = () => {
|
|||||||
};
|
};
|
||||||
const handleCreateOffer = async () => {
|
const handleCreateOffer = async () => {
|
||||||
try {
|
try {
|
||||||
|
setIsGeneratingKeys2(true);
|
||||||
setOfferData("");
|
setOfferData("");
|
||||||
setShowOfferStep(false);
|
setShowOfferStep(false);
|
||||||
setShowQRCode(false);
|
setShowQRCode(false);
|
||||||
@@ -2537,6 +2544,8 @@ var EnhancedSecureP2PChat = () => {
|
|||||||
id: Date.now(),
|
id: Date.now(),
|
||||||
timestamp: Date.now()
|
timestamp: Date.now()
|
||||||
}]);
|
}]);
|
||||||
|
} finally {
|
||||||
|
setIsGeneratingKeys2(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleCreateAnswer = async () => {
|
const handleCreateAnswer = async () => {
|
||||||
@@ -2897,6 +2906,7 @@ var EnhancedSecureP2PChat = () => {
|
|||||||
setOfferInput("");
|
setOfferInput("");
|
||||||
setAnswerInput("");
|
setAnswerInput("");
|
||||||
setShowOfferStep(false);
|
setShowOfferStep(false);
|
||||||
|
setIsGeneratingKeys2(false);
|
||||||
if (!shouldPreserveAnswerData()) {
|
if (!shouldPreserveAnswerData()) {
|
||||||
setShowAnswerStep(false);
|
setShowAnswerStep(false);
|
||||||
}
|
}
|
||||||
@@ -2954,6 +2964,7 @@ var EnhancedSecureP2PChat = () => {
|
|||||||
setAnswerInput("");
|
setAnswerInput("");
|
||||||
setShowOfferStep(false);
|
setShowOfferStep(false);
|
||||||
setShowAnswerStep(false);
|
setShowAnswerStep(false);
|
||||||
|
setIsGeneratingKeys2(false);
|
||||||
setShowQRCode(false);
|
setShowQRCode(false);
|
||||||
setQrCodeUrl("");
|
setQrCodeUrl("");
|
||||||
setShowQRScanner(false);
|
setShowQRScanner(false);
|
||||||
@@ -3154,7 +3165,9 @@ var EnhancedSecureP2PChat = () => {
|
|||||||
prevQrFrame,
|
prevQrFrame,
|
||||||
// PAKE passwords removed - using SAS verification instead
|
// PAKE passwords removed - using SAS verification instead
|
||||||
markAnswerCreated,
|
markAnswerCreated,
|
||||||
notificationIntegrationRef
|
notificationIntegrationRef,
|
||||||
|
isGeneratingKeys,
|
||||||
|
handleCreateOffer
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
// QR Scanner Modal
|
// QR Scanner Modal
|
||||||
|
|||||||
6
dist/app.js.map
vendored
6
dist/app.js.map
vendored
File diff suppressed because one or more lines are too long
57
src/app.jsx
57
src/app.jsx
@@ -281,13 +281,16 @@
|
|||||||
nextQrFrame,
|
nextQrFrame,
|
||||||
prevQrFrame,
|
prevQrFrame,
|
||||||
markAnswerCreated,
|
markAnswerCreated,
|
||||||
notificationIntegrationRef
|
notificationIntegrationRef,
|
||||||
|
isGeneratingKeys,
|
||||||
|
handleCreateOffer
|
||||||
}) => {
|
}) => {
|
||||||
const [mode, setMode] = React.useState('select');
|
const [mode, setMode] = React.useState('select');
|
||||||
const [notificationPermissionRequested, setNotificationPermissionRequested] = React.useState(false);
|
const [notificationPermissionRequested, setNotificationPermissionRequested] = React.useState(false);
|
||||||
|
|
||||||
const resetToSelect = () => {
|
const resetToSelect = () => {
|
||||||
setMode('select');
|
setMode('select');
|
||||||
|
setIsGeneratingKeys(false);
|
||||||
onClearData();
|
onClearData();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -317,12 +320,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check current permission status
|
// Check current permission status
|
||||||
const currentPermission = (typeof Notification !== 'undefined' && Notification)
|
const currentPermission = Notification.permission;
|
||||||
? Notification.permission
|
|
||||||
: 'denied';
|
|
||||||
|
|
||||||
// Only request if permission is default (not granted or denied)
|
// Only request if permission is default (not granted or denied)
|
||||||
if (typeof Notification !== 'undefined' && currentPermission === 'default') {
|
if (currentPermission === 'default') {
|
||||||
const permission = await Notification.requestPermission();
|
const permission = await Notification.requestPermission();
|
||||||
|
|
||||||
if (permission === 'granted') {
|
if (permission === 'granted') {
|
||||||
@@ -339,10 +340,9 @@
|
|||||||
// Handle error silently
|
// Handle error silently
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send welcome notification (only if Notifications API exists)
|
// Send welcome notification
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
try {
|
try {
|
||||||
if (typeof Notification === 'undefined') return;
|
|
||||||
const welcomeNotification = new Notification('SecureBit Chat', {
|
const welcomeNotification = new Notification('SecureBit Chat', {
|
||||||
body: 'Notifications enabled! You will receive alerts for new messages.',
|
body: 'Notifications enabled! You will receive alerts for new messages.',
|
||||||
icon: '/logo/icon-192x192.png',
|
icon: '/logo/icon-192x192.png',
|
||||||
@@ -363,7 +363,7 @@
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
||||||
}
|
}
|
||||||
} else if (typeof Notification !== 'undefined' && currentPermission === 'granted') {
|
} else if (currentPermission === 'granted') {
|
||||||
// Initialize notification integration immediately
|
// Initialize notification integration immediately
|
||||||
try {
|
try {
|
||||||
if (window.NotificationIntegration && webrtcManagerRef.current && !notificationIntegrationRef.current) {
|
if (window.NotificationIntegration && webrtcManagerRef.current && !notificationIntegrationRef.current) {
|
||||||
@@ -380,7 +380,6 @@
|
|||||||
// Test notification to confirm it works
|
// Test notification to confirm it works
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
try {
|
try {
|
||||||
if (typeof Notification === 'undefined') return;
|
|
||||||
const testNotification = new Notification('SecureBit Chat', {
|
const testNotification = new Notification('SecureBit Chat', {
|
||||||
body: 'Notifications are working! You will receive alerts for new messages.',
|
body: 'Notifications are working! You will receive alerts for new messages.',
|
||||||
icon: '/logo/icon-192x192.png',
|
icon: '/logo/icon-192x192.png',
|
||||||
@@ -459,6 +458,12 @@
|
|||||||
onClick: () => {
|
onClick: () => {
|
||||||
requestNotificationPermissionOnInteraction();
|
requestNotificationPermissionOnInteraction();
|
||||||
setMode('create');
|
setMode('create');
|
||||||
|
// Автоматически запускаем генерацию ключей
|
||||||
|
setTimeout(() => {
|
||||||
|
if (webrtcManagerRef.current) {
|
||||||
|
handleCreateOffer();
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
},
|
},
|
||||||
className: "card-minimal rounded-xl p-6 cursor-pointer group flex-1 create"
|
className: "card-minimal rounded-xl p-6 cursor-pointer group flex-1 create"
|
||||||
}, [
|
}, [
|
||||||
@@ -631,7 +636,7 @@
|
|||||||
className: "text-xl font-semibold text-primary mb-2"
|
className: "text-xl font-semibold text-primary mb-2"
|
||||||
}, 'Creating a secure channel')
|
}, 'Creating a secure channel')
|
||||||
]),
|
]),
|
||||||
|
|
||||||
// Step 1
|
// Step 1
|
||||||
!showAnswerStep && React.createElement('div', {
|
!showAnswerStep && React.createElement('div', {
|
||||||
key: 'step1',
|
key: 'step1',
|
||||||
@@ -654,16 +659,15 @@
|
|||||||
key: 'description',
|
key: 'description',
|
||||||
className: "text-secondary text-sm mb-4"
|
className: "text-secondary text-sm mb-4"
|
||||||
}, "Creating cryptographically strong keys and codes to protect against attacks"),
|
}, "Creating cryptographically strong keys and codes to protect against attacks"),
|
||||||
!showOfferStep && React.createElement('button', {
|
!showOfferStep && isGeneratingKeys && React.createElement('div', {
|
||||||
key: 'create-btn',
|
key: 'loading-state',
|
||||||
onClick: onCreateOffer,
|
className: "w-full py-3 px-4 rounded-lg font-medium transition-all duration-200 bg-blue-500/10 border border-blue-500/20 text-blue-400 flex items-center justify-center"
|
||||||
disabled: connectionStatus === 'connecting',
|
|
||||||
className: `w-full btn-primary text-white py-3 px-4 rounded-lg font-medium transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed`
|
|
||||||
}, [
|
}, [
|
||||||
React.createElement('i', {
|
React.createElement('i', {
|
||||||
className: 'fas fa-shield-alt mr-2'
|
key: 'spinner',
|
||||||
|
className: 'fas fa-spinner fa-spin mr-2'
|
||||||
}),
|
}),
|
||||||
'Create secure keys'
|
'Generating secure keys...'
|
||||||
]),
|
]),
|
||||||
|
|
||||||
showOfferStep && React.createElement('div', {
|
showOfferStep && React.createElement('div', {
|
||||||
@@ -1472,6 +1476,7 @@
|
|||||||
const [qrCodeUrl, setQrCodeUrl] = React.useState('');
|
const [qrCodeUrl, setQrCodeUrl] = React.useState('');
|
||||||
const [showQRScanner, setShowQRScanner] = React.useState(false);
|
const [showQRScanner, setShowQRScanner] = React.useState(false);
|
||||||
const [showQRScannerModal, setShowQRScannerModal] = React.useState(false);
|
const [showQRScannerModal, setShowQRScannerModal] = React.useState(false);
|
||||||
|
const [isGeneratingKeys, setIsGeneratingKeys] = React.useState(false);
|
||||||
|
|
||||||
|
|
||||||
const [isVerified, setIsVerified] = React.useState(false);
|
const [isVerified, setIsVerified] = React.useState(false);
|
||||||
@@ -1904,7 +1909,7 @@
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Initialize notification integration if permission was already granted
|
// Initialize notification integration if permission was already granted
|
||||||
if (typeof Notification !== 'undefined' && Notification.permission === 'granted' && window.NotificationIntegration && !notificationIntegrationRef.current) {
|
if (Notification.permission === 'granted' && window.NotificationIntegration && !notificationIntegrationRef.current) {
|
||||||
try {
|
try {
|
||||||
const integration = new window.NotificationIntegration(webrtcManagerRef.current);
|
const integration = new window.NotificationIntegration(webrtcManagerRef.current);
|
||||||
integration.init().then(() => {
|
integration.init().then(() => {
|
||||||
@@ -2800,7 +2805,7 @@
|
|||||||
const handleCreateOffer = async () => {
|
const handleCreateOffer = async () => {
|
||||||
try {
|
try {
|
||||||
// All security features are enabled by default
|
// All security features are enabled by default
|
||||||
|
setIsGeneratingKeys(true);
|
||||||
setOfferData('');
|
setOfferData('');
|
||||||
setShowOfferStep(false);
|
setShowOfferStep(false);
|
||||||
setShowQRCode(false);
|
setShowQRCode(false);
|
||||||
@@ -2904,6 +2909,8 @@
|
|||||||
id: Date.now(),
|
id: Date.now(),
|
||||||
timestamp: Date.now()
|
timestamp: Date.now()
|
||||||
}]);
|
}]);
|
||||||
|
} finally {
|
||||||
|
setIsGeneratingKeys(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3340,6 +3347,7 @@
|
|||||||
setOfferInput('');
|
setOfferInput('');
|
||||||
setAnswerInput('');
|
setAnswerInput('');
|
||||||
setShowOfferStep(false);
|
setShowOfferStep(false);
|
||||||
|
setIsGeneratingKeys(false);
|
||||||
|
|
||||||
if (!shouldPreserveAnswerData()) {
|
if (!shouldPreserveAnswerData()) {
|
||||||
setShowAnswerStep(false);
|
setShowAnswerStep(false);
|
||||||
@@ -3417,13 +3425,14 @@
|
|||||||
setRemoteVerificationConfirmed(false);
|
setRemoteVerificationConfirmed(false);
|
||||||
setBothVerificationsConfirmed(false);
|
setBothVerificationsConfirmed(false);
|
||||||
|
|
||||||
// Reset UI to initial state
|
// Reset UI to initial state
|
||||||
setOfferData('');
|
setOfferData('');
|
||||||
setAnswerData('');
|
setAnswerData('');
|
||||||
setOfferInput('');
|
setOfferInput('');
|
||||||
setAnswerInput('');
|
setAnswerInput('');
|
||||||
setShowOfferStep(false);
|
setShowOfferStep(false);
|
||||||
setShowAnswerStep(false);
|
setShowAnswerStep(false);
|
||||||
|
setIsGeneratingKeys(false);
|
||||||
setShowQRCode(false);
|
setShowQRCode(false);
|
||||||
setQrCodeUrl('');
|
setQrCodeUrl('');
|
||||||
setShowQRScanner(false);
|
setShowQRScanner(false);
|
||||||
@@ -3662,7 +3671,9 @@
|
|||||||
prevQrFrame: prevQrFrame,
|
prevQrFrame: prevQrFrame,
|
||||||
// PAKE passwords removed - using SAS verification instead
|
// PAKE passwords removed - using SAS verification instead
|
||||||
markAnswerCreated: markAnswerCreated,
|
markAnswerCreated: markAnswerCreated,
|
||||||
notificationIntegrationRef: notificationIntegrationRef
|
notificationIntegrationRef: notificationIntegrationRef,
|
||||||
|
isGeneratingKeys: isGeneratingKeys,
|
||||||
|
handleCreateOffer: handleCreateOffer
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user