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:
lockbitchat
2025-10-19 15:23:02 -04:00
parent 5ddfd1f5b3
commit 4e7f5867b5
3 changed files with 65 additions and 41 deletions

43
dist/app.js vendored
View File

@@ -268,12 +268,15 @@ var EnhancedConnectionSetup = ({
nextQrFrame,
prevQrFrame,
markAnswerCreated,
notificationIntegrationRef
notificationIntegrationRef,
isGeneratingKeys,
handleCreateOffer
}) => {
const [mode, setMode] = React.useState("select");
const [notificationPermissionRequested, setNotificationPermissionRequested] = React.useState(false);
const resetToSelect = () => {
setMode("select");
setIsGeneratingKeys(false);
onClearData();
};
const handleVerificationConfirm = () => {
@@ -293,8 +296,8 @@ var EnhancedConnectionSetup = ({
if (!window.isSecureContext && window.location.protocol !== "https:" && window.location.hostname !== "localhost") {
return;
}
const currentPermission = typeof Notification !== "undefined" && Notification ? Notification.permission : "denied";
if (typeof Notification !== "undefined" && currentPermission === "default") {
const currentPermission = Notification.permission;
if (currentPermission === "default") {
const permission = await Notification.requestPermission();
if (permission === "granted") {
try {
@@ -307,7 +310,6 @@ var EnhancedConnectionSetup = ({
}
setTimeout(() => {
try {
if (typeof Notification === "undefined") return;
const welcomeNotification = new Notification("SecureBit Chat", {
body: "Notifications enabled! You will receive alerts for new messages.",
icon: "/logo/icon-192x192.png",
@@ -323,7 +325,7 @@ var EnhancedConnectionSetup = ({
}
}, 1e3);
}
} else if (typeof Notification !== "undefined" && currentPermission === "granted") {
} else if (currentPermission === "granted") {
try {
if (window.NotificationIntegration && webrtcManagerRef.current && !notificationIntegrationRef.current) {
const integration = new window.NotificationIntegration(webrtcManagerRef.current);
@@ -334,7 +336,6 @@ var EnhancedConnectionSetup = ({
}
setTimeout(() => {
try {
if (typeof Notification === "undefined") return;
const testNotification = new Notification("SecureBit Chat", {
body: "Notifications are working! You will receive alerts for new messages.",
icon: "/logo/icon-192x192.png",
@@ -404,6 +405,11 @@ var EnhancedConnectionSetup = ({
onClick: () => {
requestNotificationPermissionOnInteraction();
setMode("create");
setTimeout(() => {
if (webrtcManagerRef.current) {
handleCreateOffer();
}
}, 100);
},
className: "card-minimal rounded-xl p-6 cursor-pointer group flex-1 create"
}, [
@@ -590,16 +596,15 @@ var EnhancedConnectionSetup = ({
key: "description",
className: "text-secondary text-sm mb-4"
}, "Creating cryptographically strong keys and codes to protect against attacks"),
!showOfferStep && React.createElement("button", {
key: "create-btn",
onClick: onCreateOffer,
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`
!showOfferStep && isGeneratingKeys && React.createElement("div", {
key: "loading-state",
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"
}, [
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", {
key: "offer-result",
@@ -1360,6 +1365,7 @@ var EnhancedSecureP2PChat = () => {
const [qrCodeUrl, setQrCodeUrl] = React.useState("");
const [showQRScanner, setShowQRScanner] = React.useState(false);
const [showQRScannerModal, setShowQRScannerModal] = React.useState(false);
const [isGeneratingKeys, setIsGeneratingKeys2] = React.useState(false);
const [isVerified, setIsVerified] = React.useState(false);
const [securityLevel, setSecurityLevel] = React.useState(null);
const [sessionTimeLeft, setSessionTimeLeft] = React.useState(0);
@@ -1672,7 +1678,7 @@ var EnhancedSecureP2PChat = () => {
handleAnswerError,
handleVerificationStateChange
);
if (typeof Notification !== "undefined" && Notification.permission === "granted" && window.NotificationIntegration && !notificationIntegrationRef.current) {
if (Notification.permission === "granted" && window.NotificationIntegration && !notificationIntegrationRef.current) {
try {
const integration = new window.NotificationIntegration(webrtcManagerRef2.current);
integration.init().then(() => {
@@ -2449,6 +2455,7 @@ var EnhancedSecureP2PChat = () => {
};
const handleCreateOffer = async () => {
try {
setIsGeneratingKeys2(true);
setOfferData("");
setShowOfferStep(false);
setShowQRCode(false);
@@ -2537,6 +2544,8 @@ var EnhancedSecureP2PChat = () => {
id: Date.now(),
timestamp: Date.now()
}]);
} finally {
setIsGeneratingKeys2(false);
}
};
const handleCreateAnswer = async () => {
@@ -2897,6 +2906,7 @@ var EnhancedSecureP2PChat = () => {
setOfferInput("");
setAnswerInput("");
setShowOfferStep(false);
setIsGeneratingKeys2(false);
if (!shouldPreserveAnswerData()) {
setShowAnswerStep(false);
}
@@ -2954,6 +2964,7 @@ var EnhancedSecureP2PChat = () => {
setAnswerInput("");
setShowOfferStep(false);
setShowAnswerStep(false);
setIsGeneratingKeys2(false);
setShowQRCode(false);
setQrCodeUrl("");
setShowQRScanner(false);
@@ -3154,7 +3165,9 @@ var EnhancedSecureP2PChat = () => {
prevQrFrame,
// PAKE passwords removed - using SAS verification instead
markAnswerCreated,
notificationIntegrationRef
notificationIntegrationRef,
isGeneratingKeys,
handleCreateOffer
})
),
// QR Scanner Modal

6
dist/app.js.map vendored

File diff suppressed because one or more lines are too long

View File

@@ -281,13 +281,16 @@
nextQrFrame,
prevQrFrame,
markAnswerCreated,
notificationIntegrationRef
notificationIntegrationRef,
isGeneratingKeys,
handleCreateOffer
}) => {
const [mode, setMode] = React.useState('select');
const [notificationPermissionRequested, setNotificationPermissionRequested] = React.useState(false);
const resetToSelect = () => {
setMode('select');
setIsGeneratingKeys(false);
onClearData();
};
@@ -317,12 +320,10 @@
}
// Check current permission status
const currentPermission = (typeof Notification !== 'undefined' && Notification)
? Notification.permission
: 'denied';
const currentPermission = Notification.permission;
// Only request if permission is default (not granted or denied)
if (typeof Notification !== 'undefined' && currentPermission === 'default') {
if (currentPermission === 'default') {
const permission = await Notification.requestPermission();
if (permission === 'granted') {
@@ -339,10 +340,9 @@
// Handle error silently
}
// Send welcome notification (only if Notifications API exists)
// Send welcome notification
setTimeout(() => {
try {
if (typeof Notification === 'undefined') return;
const welcomeNotification = new Notification('SecureBit Chat', {
body: 'Notifications enabled! You will receive alerts for new messages.',
icon: '/logo/icon-192x192.png',
@@ -363,7 +363,7 @@
}, 1000);
}
} else if (typeof Notification !== 'undefined' && currentPermission === 'granted') {
} else if (currentPermission === 'granted') {
// Initialize notification integration immediately
try {
if (window.NotificationIntegration && webrtcManagerRef.current && !notificationIntegrationRef.current) {
@@ -380,7 +380,6 @@
// Test notification to confirm it works
setTimeout(() => {
try {
if (typeof Notification === 'undefined') return;
const testNotification = new Notification('SecureBit Chat', {
body: 'Notifications are working! You will receive alerts for new messages.',
icon: '/logo/icon-192x192.png',
@@ -459,6 +458,12 @@
onClick: () => {
requestNotificationPermissionOnInteraction();
setMode('create');
// Автоматически запускаем генерацию ключей
setTimeout(() => {
if (webrtcManagerRef.current) {
handleCreateOffer();
}
}, 100);
},
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"
}, 'Creating a secure channel')
]),
// Step 1
!showAnswerStep && React.createElement('div', {
key: 'step1',
@@ -654,16 +659,15 @@
key: 'description',
className: "text-secondary text-sm mb-4"
}, "Creating cryptographically strong keys and codes to protect against attacks"),
!showOfferStep && React.createElement('button', {
key: 'create-btn',
onClick: onCreateOffer,
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`
!showOfferStep && isGeneratingKeys && React.createElement('div', {
key: 'loading-state',
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"
}, [
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', {
@@ -1472,6 +1476,7 @@
const [qrCodeUrl, setQrCodeUrl] = React.useState('');
const [showQRScanner, setShowQRScanner] = React.useState(false);
const [showQRScannerModal, setShowQRScannerModal] = React.useState(false);
const [isGeneratingKeys, setIsGeneratingKeys] = React.useState(false);
const [isVerified, setIsVerified] = React.useState(false);
@@ -1904,7 +1909,7 @@
);
// 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 {
const integration = new window.NotificationIntegration(webrtcManagerRef.current);
integration.init().then(() => {
@@ -2800,7 +2805,7 @@
const handleCreateOffer = async () => {
try {
// All security features are enabled by default
setIsGeneratingKeys(true);
setOfferData('');
setShowOfferStep(false);
setShowQRCode(false);
@@ -2904,6 +2909,8 @@
id: Date.now(),
timestamp: Date.now()
}]);
} finally {
setIsGeneratingKeys(false);
}
};
@@ -3340,6 +3347,7 @@
setOfferInput('');
setAnswerInput('');
setShowOfferStep(false);
setIsGeneratingKeys(false);
if (!shouldPreserveAnswerData()) {
setShowAnswerStep(false);
@@ -3417,13 +3425,14 @@
setRemoteVerificationConfirmed(false);
setBothVerificationsConfirmed(false);
// Reset UI to initial state
setOfferData('');
setAnswerData('');
// Reset UI to initial state
setOfferData('');
setAnswerData('');
setOfferInput('');
setAnswerInput('');
setShowOfferStep(false);
setShowAnswerStep(false);
setIsGeneratingKeys(false);
setShowQRCode(false);
setQrCodeUrl('');
setShowQRScanner(false);
@@ -3662,7 +3671,9 @@
prevQrFrame: prevQrFrame,
// PAKE passwords removed - using SAS verification instead
markAnswerCreated: markAnswerCreated,
notificationIntegrationRef: notificationIntegrationRef
notificationIntegrationRef: notificationIntegrationRef,
isGeneratingKeys: isGeneratingKeys,
handleCreateOffer: handleCreateOffer
})
),