feat(security): implement core crypto and logging hardening
- removed all logging of raw IV, JWK, session tokens, verification codes → logs now only include error codes, timestamps and short non-reversible SHA-256 hashes (first 4 bytes) - replaced global master key storage with PBKDF2-derived non-extractable AES key → master key lives only in session memory and is cleared on timeout/focus-out - added password-based derivation (PBKDF2) for master key initialization - migrated persistent key storage to AES-GCM wrapped ciphertext in IndexedDB → JWK export → encrypt with session master key → store ciphertext + IV + metadata → unwrap + import as non-extractable on restore - removed busy-wait loops and direct `window.gc()` calls → replaced with async non-blocking cleanup via setTimeout/Promise/WebWorker
This commit is contained in:
1 parent
65cc136b99
commit
6bed472e09
7 files changed
+2994
-340
No files matched your search
+1
-1
@@ -1 +1 @@
|
||||
*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media Line truncated
|
||||
*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media Line truncated
|
||||
Vendored
+1135
-149
File diff suppressed because it is too large.
Load diff
Vendored
+3
-3
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../src/crypto/EnhancedSecureCryptoUtils.js", "../src/transfer/EnhancedSecureFileTransfer.js", "../src/network/EnhancedSecureWebRTCManager.js", "../src/components/ui/SessionTimer.jsx", "../src/components/ui/Header.jsx", "../src/components/ui/DownloadApps.jsx", "../src/components/ui/UniqueFeatureSlider.jsx", "../src/components/ui/ComparisonTable.jsx", "../src/components/ui/Roadmap.jsx", "../src/components/ui/FileTransfer.jsx", "../src/scripts/app-boot.js"],
|
||||
"sourcesContent": ["class EnhancedSecureCryptoUtils {\n\n static _keyMetadata = new WeakMap();\n \n // Initialize secure logging system after class definition\n\n // Utility to sort object keys for deterministic serialization\n static sortObjectKeys(obj) {\n if (typeof obj !== 'object' || obj === null) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map(EnhancedSecureCryptoUtils.sortObjectKeys);\n }\n\n const sortedObj = {};\n Object.keys(obj).sort().forEach(key => {\n sortedObj[key] = EnhancedSecureCryptoUtils.sortObjectKeys(obj[key]);\n });\n return sortedObj;\n }\n\n // Utility to assert CryptoKey type and properties\n static assertCryptoKey(key, expectedName = null, expectedUsages = []) {\n if (!(key instanceof CryptoKey)) throw new Error('Expected CryptoKey');\n if (expectedName && key.algorithm?.name !== expectedName) {\n throw new Error(`Expected algorithm ${expectedName}, got ${key.algorithm?.name}`);\n }\n for (const u of expectedUsages) {\n if (!key.usages || !key.usages.includes(u)) {\n throw new Error(`Missing required key usage: ${u}`);\n }\n }\n }\n // Helper function to convert ArrayBuffer to Base64\n static arrayBufferToBase64(buffer) {\n let binary = '';\n const bytes = new Uint8Array(buffer);\n const len = bytes.byteLength;\n for (let i = 0; i < len; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n }\n\n // Helper function to convert Base64 to ArrayBuffer\n static base64ToArrayBuffer(base64) {\n try {\n // Validate input\n if (typeof base64 !== 'string' || !base64) {\n throw new Error('Invalid base64 input: must be a non-empty string');\n }\n\n // Remove any whitespace and validate base64 format\n const cleanBase64 = base64.trim();\n if (!/^[A-Za-z0-9+/]*={0,2}$/.test(cleanBase64)) {\n throw new Error('Invalid base64 format');\n }\n\n // Handle empty string case\n if (cleanBase64 === '') {\n return new ArrayBuffer(0);\n }\n\n const binaryString = atob(cleanBase64);\n const len = binaryString.length;\n const bytes = new Uint8Array(len);\n for (let i = 0; i < len; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes.buffer;\n } catch (error) {\n console.error('Base64 to ArrayBuffer conversion failed:', error.message);\n throw new Error(`Base64 conversion error: ${error.message}`);\n }\n }\n\n // Helper function to convert hex string to Uint8Array\n static hexToUint8Array(hexString) {\n try {\n if (!hexString || typeof hexString !== 'string') {\n throw new Error('Invalid hex string input: must be a non-empty string');\n }\n\n // Remove colons and spaces from hex string (e.g., \"aa:bb:cc\" -> \"aabbcc\")\n const cleanHex = hexString.replace(/:/g, '').replace(/\\s/g, '');\n \n // Validate hex format\n if (!/^[0-9a-fA-F]*$/.test(cleanHex)) {\n throw new Error('Invalid hex format: contains non-hex characters');\n }\n \n // Ensure even length\n if (cleanHex.length % 2 !== 0) {\n throw new Error('Invalid hex format: odd length');\n }\n\n // Convert hex string to bytes\n const bytes = new Uint8Array(cleanHex.length / 2);\n for (let i = 0; i < cleanHex.length; i += 2) {\n bytes[i / 2] = parseInt(cleanHex.substr(i, 2), 16);\n }\n \n return bytes;\n } catch (error) {\n console.error('Hex to Uint8Array conversion failed:', error.message);\n throw new Error(`Hex conversion error: ${error.message}`);\n }\n }\n\n static async encryptData(data, password) {\n try {\n const dataString = typeof data === 'string' ? data : JSON.stringify(data);\n const salt = crypto.getRandomValues(new Uint8Array(16));\n const encoder = new TextEncoder();\n const passwordBuffer = encoder.encode(password);\n\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n passwordBuffer,\n { name: 'PBKDF2' },\n false,\n ['deriveKey']\n );\n\n const key = await crypto.subtle.deriveKey(\n {\n name: 'PBKDF2',\n salt: salt,\n iterations: 100000,\n hash: 'SHA-256',\n },Line truncated
|
||||
"mappings": ";AAAA,IAAM,4BAAN,MAAM,2BAA0B;AAAA,EAE5B,OAAO,eAAe,oBAAI,QAAQ;AAAA;AAAA;AAAA,EAKlC,OAAO,eAAe,KAAK;AACvB,QAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AACzC,aAAO;AAAA,IACX;AAEA,QAAI,MAAM,QAAQ,GAAG,GAAG;AACpB,aAAO,IAAI,IAAI,2BAA0B,cAAc;AAAA,IAC3D;AAEA,UAAM,YAAY,CAAC;AACnB,WAAO,KAAK,GAAG,EAAE,KAAK,EAAE,QAAQ,SAAO;AACnC,gBAAU,GAAG,IAAI,2BAA0B,eAAe,IAAI,GAAG,CAAC;AAAA,IACtE,CAAC;AACD,WAAO;AAAA,EACX;AAAA;AAAA,EAGA,OAAO,gBAAgB,KAAK,eAAe,MAAM,iBAAiB,CAAC,GAAG;AAClE,QAAI,EAAE,eAAe,WAAY,OAAM,IAAI,MAAM,oBAAoB;AACrE,QAAI,gBAAgB,IAAI,WAAW,SAAS,cAAc;AACtD,YAAM,IAAI,MAAM,sBAAsB,YAAY,SAAS,IAAI,WAAW,IAAI,EAAE;AAAA,IACpF;AACA,eAAW,KAAK,gBAAgB;AAC5B,UAAI,CAAC,IAAI,UAAU,CAAC,IAAI,OAAO,SAAS,CAAC,GAAG;AACxC,cAAM,IAAI,MAAM,+BAA+B,CAAC,EAAE;AAAA,MACtD;AAAA,IACJ;AAAA,EACJ;AAAA;AAAA,EAEA,OAAO,oBAAoB,QAAQ;AAC/B,QAAI,SAAS;AACb,UAAM,QAAQ,IAAI,WAAW,MAAM;AACnC,UAAM,MAAM,MAAM;AAClB,aAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC1B,gBAAU,OAAO,aAAa,MAAM,CAAC,CAAC;AAAA,IAC1C;AACA,WAAO,KAAK,MAAM;AAAA,EACtB;AAAA;AAAA,EAGA,OAAO,oBAAoB,QAAQ;AAC/B,QAAI;AAEA,UAAI,OAAO,WAAW,YAAY,CAAC,QAAQ;AACvC,cAAM,IAAI,MAAM,kDAAkD;AAAA,MACtE;AAGA,YAAM,cAAc,OAAO,KAAK;AAChC,UAAI,CAAC,yBAAyB,KAAK,WAAW,GAAG;AAC7C,cAAM,IAAI,MAAM,uBAAuB;AAAA,MAC3C;AAGA,UAAI,gBAAgB,IAAI;AACpB,eAAO,IAAI,YAAY,CAAC;AAAA,MAC5B;AAEA,YAAM,eAAe,KAAK,WAAW;AACrC,YAAM,MAAM,aAAa;AACzB,YAAM,QAAQ,IAAI,WAAW,GAAG;AAChC,eAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC1B,cAAM,CAAC,IAAI,aAAa,WAAW,CAAC;AAAA,MACxC;AACA,aAAO,MAAM;AAAA,IACjB,SAAS,OAAO;AACZ,cAAQ,MAAM,4CAA4C,MAAM,OAAO;AACvE,YAAM,IAAI,MAAM,4BAA4B,MAAM,OAAO,EAAE;AAAA,IAC/D;AAAA,EACJ;AAAA;AAAA,EAGA,OAAO,gBAAgB,WAAW;AAC9B,QAAI;AACA,UAAI,CAAC,aAAa,OAAO,cAAc,UAAU;AAC7C,cAAM,IAAI,MAAM,sDAAsD;AAAA,MAC1E;AAGA,YAAM,WAAW,UAAU,QAAQ,MAAM,EAAE,EAAE,QAAQ,OAAO,EAAE;AAG9D,UAAI,CAAC,iBAAiB,KAAK,QAAQ,GAAG;AAClC,cAAM,IAAI,MAAM,iDAAiD;AAAA,MACrE;AAGA,UAAI,SAAS,SAAS,MAAM,GAAG;AAC3B,cAAM,IAAI,MAAM,gCAAgC;AAAA,MACpD;AAGA,YAAM,QAAQ,IAAI,WAAW,SAAS,SAAS,CAAC;AAChD,eAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,GAAG;AACzC,cAAM,IAAI,CAAC,IAAI,SAAS,SAAS,OAAO,GAAG,CAAC,GAAG,EAAE;AAAA,MACrD;AAEA,aAAO;AAAA,IACX,SAAS,OAAO;AACZ,cAAQ,MAAM,wCAAwC,MAAM,OAAO;AACnE,YAAM,IAAI,MAAM,yBAAyB,MAAM,OAAO,EAAE;AAAA,IAC5D;AAAA,EACJ;AAAA,EAEA,aAAa,YAAY,MAAM,UAAU;AACrC,QAAI;AACA,YAAM,aAAa,OAAO,SAAS,WAAW,OAAO,KAAK,UAAU,IAAI;AACxE,YAAM,OAAO,OAAO,gBAAgB,IAAI,WAAW,EAAE,CAAC;AACtD,YAAM,UAAU,IAAI,YAAY;AAChC,YAAM,iBAAiB,QAAQ,OAAO,QAAQ;AAE9C,YAAM,cAAc,MAAM,OAAO,OAAO;AAAA,QACpC;AAAA,QACA;AAAA,QACA,EAAE,MAAM,SAAS;AAAA,QACjB;AAAA,QACA,CAAC,WAAW;AAAA,MAChB;AAEA,YAAM,MAAM,MAAM,OAAO,OAAO;AAAA,QAC5B;AAAA,UACI,MAAM;AAAA,UACN;AAAA,UACA,YAAY;AAAA,UACZ,MAAM;AAAA,QACV;AAAA,QACA;AAAA,QACA,EAAE,MAAM,WAAW,QAAQ,IAAI;AAAA,QAC/B;AAAA,QACA,CAAC,SAAS;AAAA,MACd;AAEA,YAAM,KAAK,OAAO,gBAAgB,IAAI,WAAW,EAAE,CAAC;AACpD,YAAM,aAAa,QAAQ,OAAO,UAAU;AAC5C,YAAM,YAAY,MAAM,OAAO,OAAO;AAAA,QAClC,EAAE,MAAM,WAAW,GAAO;AAAA,QAC1B;AAAA,QACA;AAAA,MACJ;AAEA,YAAM,mBAAmB;AAAA,QACrB,SAAS;AAAA,QACT,MAAM,MAAM,KAAK,IAAI;AAAA,QACrB,IAAI,MAAM,KAAK,EAAE;AAAA,QACjB,MAAM,MAAM,KAAK,IAAI,WAAW,SAAS,CAAC;AAAA,QAC1C,WAAW,KAAK,IAAI;AAAA,MACxB;AAEA,YAAM,gBAAgB,KAAK,UAAU,gBAAgB;AACrD,aAAO,2BAA0B,oBAAoB,IAAI,YAAY,EAAE,OAAO,aAAa,EAAE,MAAM;AAAA,IAEvG,SAAS,OAAO;AACZ,cAAQ,MAAM,sBAAsB,MAAM,OAAO;AACjD,YAAM,IAAI,MAAM,qBAAqB,MAAM,OAAO,EAAE;AAAA,IACxD;AAAA,EACJ;AAAA,EAEI,aAAa,YAAY,eAAe,UAAU;AAClD,QAAI;AACA,YAAM,gBAAgB,2BAA0B,oBAAoB,aAAa;AACjF,YAAM,gBAAgB,IAAI,YAAY,EAAE,OAAO,aAAa;AAC5D,YAAM,mBAAmB,KAAK,MAAM,aAAa;AAEjD,UAAI,CAAC,iBAAiB,WAAW,CAAC,iBAAiB,QAAQ,CAAC,iBAAiB,MAAM,CAAC,iBAAiB,MAAM;AACvG,cAAM,IAAI,MAAM,+BAA+B;AAAA,MACnD;AAEA,YAAM,OAAO,IAAI,WAAW,iBAAiB,IAAI;AACjD,YAAM,KAAK,IAAI,WAAW,iBAAiB,EAAE;AAC7C,YAAM,YAAY,IAAI,WAAW,iBAAiB,IAAI;AAEtD,YAAM,UAAU,IAAI,YAAY;AAChC,YAAM,iBAAiB,QAAQ,OAAO,QAAQ;AAE9C,YAAM,cAAc,MAAM,OAAO,OAAO;AAAA,QACpC;AAAA,QACA;AAAA,QACA,EAAE,MAAM,SAAS;AAAA,QACjB;AAAA,QACA,CAAC,WAAW;AAAA,MAChB;AAEA,YAAM,MAAM,MAAM,OAAO,OAAO;AAAA,QAC5B;AAAA,UACI,MAAM;AAAA,UACN;AAAA,UACA,YAAY;AAAA,UACZ,MAAM;AAAA,QACV;AAAA,QACA;AAAA,QACA,EAAE,MAAM,WAAW,QAAQ,IAAI;AAAA,QAC/B;AAAA,QACA,CAAC,SAAS;AAAA,MACd;AAEA,YAAM,YAAY,MAAM,OAAO,OAAO;AAAA,QAClC,EAAE,MAAM,WAAW,GAAG;AAAA,QACtB;AAAA,QACA;AAAA,MACJ;AAEA,YAAM,kBAAkB,IAAI,YAAY,EAAE,OAAO,SAAS;AAE1D,UAAI;AACA,eAAO,KAAK,MAAM,eAAe;AAAA,MACrC,QAAQ;AACJ,eAAO;AAAA,MACX;AAAA,IAEJ,SAAS,OAAO;AACZ,cAAQ,MAAM,sBAAsB,MAAM,OAAO;AACjD,YAAM,IAAI,MAAM,qBAAqB,MAAM,OAAO,EAAE;AAAA,IACxD;AAAA,EACJ;AAAA;AAAA,EAIA,OAAO,yBAAyB;AAC5B,UAAM,QAAQ;AACd,UAAM,SAAS;AACf,UAAM,eAAe,IAAI,YAAY,MAAM;AAC3C,WAAO,gBAAgB,YAAY;AAEnC,QAAI,WAAW;AACf,aAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC7B,kBAAY,MAAM,aAAa,CAAC,IAAI,MAAM,MAAM;AAAA,IACpD;AACA,WAAO;AAAA,EACX;AAAA;AAAA,EAGA,aAAa,uBAAuB,iBAAiB;AACjD,QAAI,QAAQ;AACZ,UAAM,WAAW;AACjB,UAAM,sBAAsB,CAAC;AAE7B,QAAI;AAEA,UAAI,CAAC,mBAAmB,CAAC,gBAAgB,kBAAkB;AACvD,gBAAQ,KAAK,oEAAoE;AACjF,eAAO;AAAA,UACH,OAAO;AAAA,UACP,OAAO;AAAA,UACP,OAAO;AAAA,UACP,qBAAqB,CAAC;AAAA,UACtB,WAAW,KAAK,IAAI;AAAA,UACpB,SAAS;AAAA,UACT,YAAY;AAAA,QAChB;AAAA,MACJ;AAGA,YAAM,cAAc;AACpB,YAAM,gBAAgB;AAGtB,UAAI;AACA,cAAM,mBAAmB,MAAM,2BAA0B,iBAAiB,eAAe;AACzF,YAAI,iBAAiB,QAAQ;AACzB,mBAAS;AACT,8BAAoB,mBAAmB,EAAE,QAAQ,MAAM,SAAS,Line truncated
|
||||
"names": ["fileMessageTypes", "attempts", "start", "start", "attempts", "chunk", "fileMessageTypes", "window", "webrtcManager"]
|
||||
"sourcesContent": ["class EnhancedSecureCryptoUtils {\n\n static _keyMetadata = new WeakMap();\n \n // Initialize secure logging system after class definition\n\n // Utility to sort object keys for deterministic serialization\n static sortObjectKeys(obj) {\n if (typeof obj !== 'object' || obj === null) {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map(EnhancedSecureCryptoUtils.sortObjectKeys);\n }\n\n const sortedObj = {};\n Object.keys(obj).sort().forEach(key => {\n sortedObj[key] = EnhancedSecureCryptoUtils.sortObjectKeys(obj[key]);\n });\n return sortedObj;\n }\n\n // Utility to assert CryptoKey type and properties\n static assertCryptoKey(key, expectedName = null, expectedUsages = []) {\n if (!(key instanceof CryptoKey)) throw new Error('Expected CryptoKey');\n if (expectedName && key.algorithm?.name !== expectedName) {\n throw new Error(`Expected algorithm ${expectedName}, got ${key.algorithm?.name}`);\n }\n for (const u of expectedUsages) {\n if (!key.usages || !key.usages.includes(u)) {\n throw new Error(`Missing required key usage: ${u}`);\n }\n }\n }\n // Helper function to convert ArrayBuffer to Base64\n static arrayBufferToBase64(buffer) {\n let binary = '';\n const bytes = new Uint8Array(buffer);\n const len = bytes.byteLength;\n for (let i = 0; i < len; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n }\n\n // Helper function to convert Base64 to ArrayBuffer\n static base64ToArrayBuffer(base64) {\n try {\n // Validate input\n if (typeof base64 !== 'string' || !base64) {\n throw new Error('Invalid base64 input: must be a non-empty string');\n }\n\n // Remove any whitespace and validate base64 format\n const cleanBase64 = base64.trim();\n if (!/^[A-Za-z0-9+/]*={0,2}$/.test(cleanBase64)) {\n throw new Error('Invalid base64 format');\n }\n\n // Handle empty string case\n if (cleanBase64 === '') {\n return new ArrayBuffer(0);\n }\n\n const binaryString = atob(cleanBase64);\n const len = binaryString.length;\n const bytes = new Uint8Array(len);\n for (let i = 0; i < len; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes.buffer;\n } catch (error) {\n console.error('Base64 to ArrayBuffer conversion failed:', error.message);\n throw new Error(`Base64 conversion error: ${error.message}`);\n }\n }\n\n // Helper function to convert hex string to Uint8Array\n static hexToUint8Array(hexString) {\n try {\n if (!hexString || typeof hexString !== 'string') {\n throw new Error('Invalid hex string input: must be a non-empty string');\n }\n\n // Remove colons and spaces from hex string (e.g., \"aa:bb:cc\" -> \"aabbcc\")\n const cleanHex = hexString.replace(/:/g, '').replace(/\\s/g, '');\n \n // Validate hex format\n if (!/^[0-9a-fA-F]*$/.test(cleanHex)) {\n throw new Error('Invalid hex format: contains non-hex characters');\n }\n \n // Ensure even length\n if (cleanHex.length % 2 !== 0) {\n throw new Error('Invalid hex format: odd length');\n }\n\n // Convert hex string to bytes\n const bytes = new Uint8Array(cleanHex.length / 2);\n for (let i = 0; i < cleanHex.length; i += 2) {\n bytes[i / 2] = parseInt(cleanHex.substr(i, 2), 16);\n }\n \n return bytes;\n } catch (error) {\n console.error('Hex to Uint8Array conversion failed:', error.message);\n throw new Error(`Hex conversion error: ${error.message}`);\n }\n }\n\n static async encryptData(data, password) {\n try {\n const dataString = typeof data === 'string' ? data : JSON.stringify(data);\n const salt = crypto.getRandomValues(new Uint8Array(16));\n const encoder = new TextEncoder();\n const passwordBuffer = encoder.encode(password);\n\n const keyMaterial = await crypto.subtle.importKey(\n 'raw',\n passwordBuffer,\n { name: 'PBKDF2' },\n false,\n ['deriveKey']\n );\n\n const key = await crypto.subtle.deriveKey(\n {\n name: 'PBKDF2',\n salt: salt,\n iterations: 100000,\n hash: 'SHA-256',\n },Line truncated
|
||||
"mappings": "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 truncated
|
||||
"names": ["fileMessageTypes", "attempts", "start", "error", "attempts", "chunk", "fileMessageTypes", "window", "start", "webrtcManager"]
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
// Пример использования новой асинхронной системы очистки
|
||||
import { EnhancedSecureWebRTCManager } from './src/network/EnhancedSecureWebRTCManager.js';
|
||||
|
||||
// Создание менеджера WebRTC с асинхронной очисткой
|
||||
const webrtcManager = new EnhancedSecureWebRTCManager(
|
||||
(message) => console.log('Received:', message),
|
||||
(status) => console.log('Status:', status),
|
||||
(keyData) => console.log('Key exchange:', keyData),
|
||||
(verificationData) => console.log('Verification required:', verificationData)
|
||||
);
|
||||
|
||||
// Демонстрация асинхронной очистки
|
||||
async function demonstrateAsyncCleanup() {
|
||||
console.log('=== Демонстрация асинхронной системы очистки ===');
|
||||
|
||||
try {
|
||||
// 1. Демонстрация естественной очистки памяти
|
||||
console.log('\n1. Тест естественной очистки памяти...');
|
||||
const startTime = performance.now();
|
||||
|
||||
await webrtcManager._performNaturalCleanup();
|
||||
|
||||
const endTime = performance.now();
|
||||
console.log(`✅ Естественная очистка завершена за ${(endTime - startTime).toFixed(2)}ms`);
|
||||
console.log(' - Без блокировки UI');
|
||||
console.log(' - Без принудительного window.gc()');
|
||||
console.log(' - Использует естественные циклы сборки мусора');
|
||||
|
||||
// 2. Демонстрация асинхронного sleep
|
||||
console.log('\n2. Тест асинхронного sleep (замена busy-wait)...');
|
||||
const sleepStart = performance.now();
|
||||
|
||||
await webrtcManager._asyncSleep(50); // 50ms без блокировки
|
||||
|
||||
const sleepEnd = performance.now();
|
||||
console.log(`✅ Асинхронный sleep завершен за ${(sleepEnd - sleepStart).toFixed(2)}ms`);
|
||||
console.log(' - UI остается отзывчивым');
|
||||
console.log(' - Нет busy-wait циклов');
|
||||
|
||||
// 3. Демонстрация батчевых операций
|
||||
console.log('\n3. Тест батчевых операций...');
|
||||
const batchStart = performance.now();
|
||||
|
||||
// Создаем массив "тяжелых" операций
|
||||
const heavyOperations = Array.from({ length: 100 }, (_, i) =>
|
||||
async () => {
|
||||
// Симуляция тяжелой операции
|
||||
await webrtcManager._asyncSleep(1);
|
||||
return `operation_${i}`;
|
||||
}
|
||||
);
|
||||
|
||||
const results = await webrtcManager._batchAsyncOperation(heavyOperations, 10, 2);
|
||||
|
||||
const batchEnd = performance.now();
|
||||
console.log(`✅ Батчевые операции завершены за ${(batchEnd - batchStart).toFixed(2)}ms`);
|
||||
console.log(` - Обработано ${results.length} операций`);
|
||||
console.log(' - UI не блокировался благодаря батчингу');
|
||||
console.log(' - Задержки между батчами предотвращают зависание');
|
||||
|
||||
// 4. Демонстрация WebWorker очистки (если доступен)
|
||||
console.log('\n4. Тест WebWorker очистки...');
|
||||
const workerStart = performance.now();
|
||||
|
||||
const cleanupData = {
|
||||
type: 'cleanup_arrays',
|
||||
data: { count: 1000 }
|
||||
};
|
||||
|
||||
const workerResult = await webrtcManager._performHeavyCleanup(cleanupData);
|
||||
|
||||
const workerEnd = performance.now();
|
||||
console.log(`✅ WebWorker очистка завершена за ${(workerEnd - workerStart).toFixed(2)}ms`);
|
||||
console.log(` - Результат: ${JSON.stringify(workerResult)}`);
|
||||
console.log(' - Тяжелые операции выполнены в фоновом потоке');
|
||||
console.log(' - Основной поток не блокировался');
|
||||
|
||||
// 5. Демонстрация запланированной очистки
|
||||
console.log('\n5. Тест запланированной очистки...');
|
||||
const scheduleStart = performance.now();
|
||||
|
||||
const cleanupPromise = webrtcManager._scheduleAsyncCleanup(async () => {
|
||||
console.log(' 🧹 Выполняется запланированная очистка...');
|
||||
await webrtcManager._asyncSleep(20);
|
||||
console.log(' ✅ Запланированная очистка завершена');
|
||||
}, 10); // Задержка 10ms
|
||||
|
||||
await cleanupPromise;
|
||||
|
||||
const scheduleEnd = performance.now();
|
||||
console.log(`✅ Запланированная очистка завершена за ${(scheduleEnd - scheduleStart).toFixed(2)}ms`);
|
||||
console.log(' - Очистка выполнена с задержкой');
|
||||
console.log(' - Не блокирует текущий поток выполнения');
|
||||
|
||||
// 6. Сравнение производительности
|
||||
console.log('\n6. Сравнение с старой системой...');
|
||||
console.log('📊 Преимущества новой системы:');
|
||||
console.log(' ✅ Нет busy-wait циклов');
|
||||
console.log(' ✅ Нет принудительного window.gc()');
|
||||
console.log(' ✅ UI остается отзывчивым');
|
||||
console.log(' ✅ WebWorker для тяжелых операций');
|
||||
console.log(' ✅ Батчинг предотвращает блокировки');
|
||||
console.log(' ✅ Естественная сборка мусора');
|
||||
|
||||
console.log('\n❌ Проблемы старой системы (исправлены):');
|
||||
console.log(' ❌ while (Date.now() - start < 10) {} - busy-wait');
|
||||
console.log(' ❌ window.gc() - принудительная сборка мусора');
|
||||
console.log(' ❌ Блокировка UI при очистке');
|
||||
console.log(' ❌ Синхронные тяжелые операции');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Ошибка демонстрации:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Демонстрация мониторинга производительности
|
||||
async function demonstratePerformanceMonitoring() {
|
||||
console.log('\n=== Мониторинг производительности ===');
|
||||
|
||||
// Мониторинг времени выполнения операций
|
||||
const operations = [
|
||||
{ name: 'Естественная очистка', fn: () => webrtcManager._performNaturalCleanup() },
|
||||
{ name: 'Асинхронный sleep 10ms', fn: () => webrtcManager._asyncSleep(10) },
|
||||
{ name: 'Батчевая операция', fn: () => webrtcManager._batchAsyncOperation([
|
||||
async () => 'test1',
|
||||
async () => 'test2',
|
||||
async () => 'test3'
|
||||
], 2, 1) }
|
||||
];
|
||||
|
||||
for (const operation of operations) {
|
||||
const start = performance.now();
|
||||
await operation.fn();
|
||||
const end = performance.now();
|
||||
|
||||
console.log(`⏱️ ${operation.name}: ${(end - start).toFixed(2)}ms`);
|
||||
}
|
||||
|
||||
// Проверка доступности WebWorker
|
||||
if (typeof Worker !== 'undefined') {
|
||||
console.log('✅ WebWorker доступен - тяжелые операции будут выполняться в фоне');
|
||||
} else {
|
||||
console.log('⚠️ WebWorker недоступен - fallback на батчинг в основном потоке');
|
||||
}
|
||||
}
|
||||
|
||||
// Запуск демонстрации
|
||||
console.log('🚀 Запуск демонстрации асинхронной системы очистки...');
|
||||
|
||||
demonstrateAsyncCleanup()
|
||||
.then(() => demonstratePerformanceMonitoring())
|
||||
.then(() => {
|
||||
console.log('\n🎉 Демонстрация завершена успешно!');
|
||||
console.log('💡 Новая система обеспечивает:');
|
||||
console.log(' • Отзывчивый UI');
|
||||
console.log(' • Эффективную очистку памяти');
|
||||
console.log(' • Отсутствие блокировок');
|
||||
console.log(' • Использование WebWorker для тяжелых операций');
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('❌ Ошибка демонстрации:', error);
|
||||
});
|
||||
@@ -0,0 +1,61 @@
|
||||
// Пример использования новой системы мастер-ключей
|
||||
import { EnhancedSecureWebRTCManager } from './src/network/EnhancedSecureWebRTCManager.js';
|
||||
|
||||
// Создание менеджера WebRTC
|
||||
const webrtcManager = new EnhancedSecureWebRTCManager(
|
||||
(message) => console.log('Received:', message),
|
||||
(status) => console.log('Status:', status),
|
||||
(keyData) => console.log('Key exchange:', keyData),
|
||||
(verificationData) => console.log('Verification required:', verificationData)
|
||||
);
|
||||
|
||||
// Настройка callback для запроса пароля
|
||||
webrtcManager.setMasterKeyPasswordCallback((isRetry, callback) => {
|
||||
// В реальном приложении здесь должен быть UI для ввода пароля
|
||||
const message = isRetry ?
|
||||
'Неверный пароль. Введите мастер-пароль повторно:' :
|
||||
'Введите мастер-пароль для разблокировки безопасного хранилища:';
|
||||
|
||||
// Пример с prompt (в реальном приложении используйте модальное окно)
|
||||
const password = prompt(message);
|
||||
callback(password);
|
||||
});
|
||||
|
||||
// Настройка callback для истечения сессии
|
||||
webrtcManager.setMasterKeySessionExpiredCallback((reason) => {
|
||||
console.warn(`Сессия мастер-ключа истекла: ${reason}`);
|
||||
|
||||
// Уведомить пользователя
|
||||
if (reason === 'inactivity') {
|
||||
alert('Сессия заблокирована из-за неактивности. Потребуется повторный ввод пароля.');
|
||||
} else if (reason === 'timeout') {
|
||||
alert('Сессия истекла по таймауту. Потребуется повторный ввод пароля.');
|
||||
}
|
||||
});
|
||||
|
||||
// Проверка статуса мастер-ключа
|
||||
console.log('Мастер-ключ разблокирован:', webrtcManager.isMasterKeyUnlocked());
|
||||
console.log('Статус сессии:', webrtcManager.getMasterKeySessionStatus());
|
||||
|
||||
// Ручная блокировка мастер-ключа
|
||||
// webrtcManager.lockMasterKey();
|
||||
|
||||
// Пример использования в реальном приложении:
|
||||
async function initializeSecureConnection() {
|
||||
try {
|
||||
// При первом обращении к зашифрованным ключам будет запрошен пароль
|
||||
const offer = await webrtcManager.createSecureOffer();
|
||||
console.log('Secure offer created:', offer);
|
||||
|
||||
// Мастер-ключ теперь разблокирован и будет автоматически заблокирован:
|
||||
// - через 15 минут бездействия
|
||||
// - через 5 минут после потери фокуса окна
|
||||
// - при ручном вызове lockMasterKey()
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to create secure offer:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Запуск примера
|
||||
initializeSecureConnection();
|
||||
@@ -0,0 +1,170 @@
|
||||
// Пример использования новой системы персистентного хранения ключей
|
||||
import {
|
||||
EnhancedSecureWebRTCManager,
|
||||
SecureMasterKeyManager,
|
||||
SecureIndexedDBWrapper,
|
||||
SecurePersistentKeyStorage
|
||||
} from './src/network/EnhancedSecureWebRTCManager.js';
|
||||
|
||||
// Создание менеджера WebRTC с персистентным хранением
|
||||
const webrtcManager = new EnhancedSecureWebRTCManager(
|
||||
(message) => console.log('Received:', message),
|
||||
(status) => console.log('Status:', status),
|
||||
(keyData) => console.log('Key exchange:', keyData),
|
||||
(verificationData) => console.log('Verification required:', verificationData)
|
||||
);
|
||||
|
||||
// Настройка callback для запроса пароля
|
||||
webrtcManager.setMasterKeyPasswordCallback((isRetry, callback) => {
|
||||
const message = isRetry ?
|
||||
'Неверный пароль. Введите мастер-пароль повторно:' :
|
||||
'Введите мастер-пароль для разблокировки хранилища ключей:';
|
||||
|
||||
// В реальном приложении используйте безопасный UI
|
||||
const password = prompt(message);
|
||||
callback(password);
|
||||
});
|
||||
|
||||
// Настройка callback для истечения сессии
|
||||
webrtcManager.setMasterKeySessionExpiredCallback((reason) => {
|
||||
console.warn(`Сессия мастер-ключа истекла: ${reason}`);
|
||||
alert(`Сессия заблокирована: ${reason}. Потребуется повторный ввод пароля.`);
|
||||
});
|
||||
|
||||
// Демонстрация работы с персистентным хранением
|
||||
async function demonstratePersistentStorage() {
|
||||
try {
|
||||
console.log('=== Демонстрация персистентного хранения ключей ===');
|
||||
|
||||
// 1. Создание и сохранение extractable ключа
|
||||
console.log('\n1. Создание extractable ключа для демонстрации...');
|
||||
const testKey = await crypto.subtle.generateKey(
|
||||
{
|
||||
name: 'AES-GCM',
|
||||
length: 256
|
||||
},
|
||||
true, // extractable = true для персистентного хранения
|
||||
['encrypt', 'decrypt']
|
||||
);
|
||||
|
||||
// 2. Сохранение ключа (автоматически зашифруется и сохранится в IndexedDB)
|
||||
console.log('2. Сохранение ключа в персистентное хранилище...');
|
||||
const keyId = 'demo_persistent_key_' + Date.now();
|
||||
const stored = await webrtcManager._secureKeyStorage.storeKey(keyId, testKey, {
|
||||
purpose: 'demonstration',
|
||||
algorithm: 'AES-GCM'
|
||||
});
|
||||
|
||||
if (stored) {
|
||||
console.log('✅ Ключ успешно сохранен в зашифрованном виде в IndexedDB');
|
||||
} else {
|
||||
console.log('❌ Ошибка сохранения ключа');
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Получение статистики хранилища
|
||||
console.log('\n3. Статистика хранилища:');
|
||||
const stats = await webrtcManager._secureKeyStorage.getStorageStats();
|
||||
console.log('Статистика:', JSON.stringify(stats, null, 2));
|
||||
|
||||
// 4. Список всех ключей
|
||||
console.log('\n4. Список всех ключей:');
|
||||
const allKeys = await webrtcManager._secureKeyStorage.listAllKeys();
|
||||
console.log('Ключи:', JSON.stringify(allKeys, null, 2));
|
||||
|
||||
// 5. Симуляция перезапуска приложения (очистка памяти)
|
||||
console.log('\n5. Симуляция перезапуска приложения...');
|
||||
webrtcManager._secureKeyStorage._keyReferences.clear();
|
||||
console.log('Память очищена. Ключи остались только в IndexedDB.');
|
||||
|
||||
// 6. Восстановление ключа из IndexedDB
|
||||
console.log('\n6. Восстановление ключа из IndexedDB...');
|
||||
const restoredKey = await webrtcManager._secureKeyStorage.retrieveKey(keyId);
|
||||
|
||||
if (restoredKey) {
|
||||
console.log('✅ Ключ успешно восстановлен из IndexedDB как non-extractable');
|
||||
console.log('Тип ключа:', restoredKey.type);
|
||||
console.log('Алгоритм:', restoredKey.algorithm.name);
|
||||
console.log('Extractable:', restoredKey.extractable); // Должно быть false
|
||||
} else {
|
||||
console.log('❌ Ошибка восстановления ключа');
|
||||
}
|
||||
|
||||
// 7. Тест шифрования с восстановленным ключом
|
||||
console.log('\n7. Тест шифрования с восстановленным ключом...');
|
||||
const testData = new TextEncoder().encode('Тестовые данные для шифрования');
|
||||
const iv = crypto.getRandomValues(new Uint8Array(12));
|
||||
|
||||
const encrypted = await crypto.subtle.encrypt(
|
||||
{ name: 'AES-GCM', iv },
|
||||
restoredKey,
|
||||
testData
|
||||
);
|
||||
|
||||
const decrypted = await crypto.subtle.decrypt(
|
||||
{ name: 'AES-GCM', iv },
|
||||
restoredKey,
|
||||
encrypted
|
||||
);
|
||||
|
||||
const decryptedText = new TextDecoder().decode(decrypted);
|
||||
console.log('✅ Шифрование/расшифровка успешно:', decryptedText);
|
||||
|
||||
// 8. Очистка демонстрационных данных
|
||||
console.log('\n8. Очистка демонстрационных данных...');
|
||||
await webrtcManager._secureKeyStorage.deleteKey(keyId);
|
||||
console.log('✅ Демонстрационный ключ удален');
|
||||
|
||||
console.log('\n=== Демонстрация завершена ===');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Ошибка демонстрации:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Демонстрация безопасности
|
||||
async function demonstrateSecurity() {
|
||||
console.log('\n=== Демонстрация безопасности ===');
|
||||
|
||||
try {
|
||||
// Попытка прямого доступа к IndexedDB
|
||||
const request = indexedDB.open('SecureKeyStorage');
|
||||
request.onsuccess = (event) => {
|
||||
const db = event.target.result;
|
||||
const transaction = db.transaction(['encrypted_keys'], 'readonly');
|
||||
const store = transaction.objectStore('encrypted_keys');
|
||||
const getAllRequest = store.getAll();
|
||||
|
||||
getAllRequest.onsuccess = () => {
|
||||
const keys = getAllRequest.result;
|
||||
console.log('🔍 Прямой доступ к IndexedDB:');
|
||||
|
||||
if (keys.length > 0) {
|
||||
const firstKey = keys[0];
|
||||
console.log('📦 Найден зашифрованный ключ:');
|
||||
console.log('- ID:', firstKey.keyId);
|
||||
console.log('- Зашифрованные данные (первые 20 байт):',
|
||||
Array.from(firstKey.encryptedData.slice(0, 20))
|
||||
.map(b => b.toString(16).padStart(2, '0')).join(' '));
|
||||
console.log('- IV:', Array.from(firstKey.iv)
|
||||
.map(b => b.toString(16).padStart(2, '0')).join(' '));
|
||||
console.log('✅ Данные зашифрованы - невозможно извлечь JWK без мастер-ключа!');
|
||||
} else {
|
||||
console.log('📭 Нет сохраненных ключей в IndexedDB');
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.error('Ошибка проверки безопасности:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Запуск демонстрации
|
||||
console.log('Запуск демонстрации персистентного хранения ключей...');
|
||||
console.log('При первом запуске будет запрошен мастер-пароль.');
|
||||
|
||||
// Последовательный запуск демонстраций
|
||||
demonstratePersistentStorage()
|
||||
.then(() => demonstrateSecurity())
|
||||
.catch(error => console.error('Ошибка:', error));
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user