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,
|
||||
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
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,
|
||||
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
|
||||
})
|
||||
),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user