Browse Source
Add PKI backup dialog, add reminder toast to suggest backing up private key.pull/384/head
committed by
GitHub
17 changed files with 730 additions and 300 deletions
@ -89,6 +89,9 @@ importers: |
|||
immer: |
|||
specifier: ^10.1.1 |
|||
version: 10.1.1 |
|||
js-cookie: |
|||
specifier: ^3.0.5 |
|||
version: 3.0.5 |
|||
lucide-react: |
|||
specifier: ^0.363.0 |
|||
version: 0.363.0([email protected]) |
|||
@ -127,7 +130,7 @@ importers: |
|||
version: 3.0.6([email protected]) |
|||
vite-plugin-node-polyfills: |
|||
specifier: ^0.22.0 |
|||
version: 0.22.0([email protected]4.0)([email protected](@types/[email protected])) |
|||
version: 0.22.0([email protected]9.1)([email protected](@types/[email protected])) |
|||
zustand: |
|||
specifier: 4.5.2 |
|||
version: 4.5.2(@types/[email protected])([email protected])([email protected]) |
|||
@ -147,6 +150,9 @@ importers: |
|||
'@types/chrome': |
|||
specifier: ^0.0.263 |
|||
version: 0.0.263 |
|||
'@types/js-cookie': |
|||
specifier: ^3.0.6 |
|||
version: 3.0.6 |
|||
'@types/node': |
|||
specifier: ^20.14.9 |
|||
version: 20.14.9 |
|||
@ -173,7 +179,7 @@ importers: |
|||
version: 8.4.38 |
|||
rollup-plugin-visualizer: |
|||
specifier: ^5.12.0 |
|||
version: 5.12.0([email protected]4.0) |
|||
version: 5.12.0([email protected]9.1) |
|||
tailwindcss: |
|||
specifier: ^3.4.4 |
|||
version: 3.4.4 |
|||
@ -1165,83 +1171,98 @@ packages: |
|||
rollup: |
|||
optional: true |
|||
|
|||
'@rollup/[email protected]4.0': |
|||
resolution: {integrity: sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==} |
|||
'@rollup/[email protected]9.1': |
|||
resolution: {integrity: sha512-ssKhA8RNltTZLpG6/QNkCSge+7mBQGUqJRisZ2MDQcEGaK93QESEgWK2iOpIDZ7k9zPVkG5AS3ksvD5ZWxmItw==} |
|||
cpu: [arm] |
|||
os: [android] |
|||
|
|||
'@rollup/[email protected]4.0': |
|||
resolution: {integrity: sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==} |
|||
'@rollup/[email protected]9.1': |
|||
resolution: {integrity: sha512-CaRfrV0cd+NIIcVVN/jx+hVLN+VRqnuzLRmfmlzpOzB87ajixsN/+9L5xNmkaUUvEbI5BmIKS+XTwXsHEb65Ew==} |
|||
cpu: [arm64] |
|||
os: [android] |
|||
|
|||
'@rollup/[email protected]4.0': |
|||
resolution: {integrity: sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==} |
|||
'@rollup/[email protected]9.1': |
|||
resolution: {integrity: sha512-2ORr7T31Y0Mnk6qNuwtyNmy14MunTAMx06VAPI6/Ju52W10zk1i7i5U3vlDRWjhOI5quBcrvhkCHyF76bI7kEw==} |
|||
cpu: [arm64] |
|||
os: [darwin] |
|||
|
|||
'@rollup/[email protected]4.0': |
|||
resolution: {integrity: sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==} |
|||
'@rollup/[email protected]9.1': |
|||
resolution: {integrity: sha512-j/Ej1oanzPjmN0tirRd5K2/nncAhS9W6ICzgxV+9Y5ZsP0hiGhHJXZ2JQ53iSSjj8m6cRY6oB1GMzNn2EUt6Ng==} |
|||
cpu: [x64] |
|||
os: [darwin] |
|||
|
|||
'@rollup/[email protected]': |
|||
resolution: {integrity: sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==} |
|||
'@rollup/[email protected]': |
|||
resolution: {integrity: sha512-91C//G6Dm/cv724tpt7nTyP+JdN12iqeXGFM1SqnljCmi5yTXriH7B1r8AD9dAZByHpKAumqP1Qy2vVNIdLZqw==} |
|||
cpu: [arm64] |
|||
os: [freebsd] |
|||
|
|||
'@rollup/[email protected]': |
|||
resolution: {integrity: sha512-hEioiEQ9Dec2nIRoeHUP6hr1PSkXzQaCUyqBDQ9I9ik4gCXQZjJMIVzoNLBRGet+hIUb3CISMh9KXuCcWVW/8w==} |
|||
cpu: [x64] |
|||
os: [freebsd] |
|||
|
|||
'@rollup/[email protected]': |
|||
resolution: {integrity: sha512-Py5vFd5HWYN9zxBv3WMrLAXY3yYJ6Q/aVERoeUFwiDGiMOWsMs7FokXihSOaT/PMWUty/Pj60XDQndK3eAfE6A==} |
|||
cpu: [arm] |
|||
os: [linux] |
|||
|
|||
'@rollup/[email protected]': |
|||
resolution: {integrity: sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==} |
|||
'@rollup/[email protected]9.1': |
|||
resolution: {integrity: sha512-RiWpGgbayf7LUcuSNIbahr0ys2YnEERD4gYdISA06wa0i8RALrnzflh9Wxii7zQJEB2/Eh74dX4y/sHKLWp5uQ==} |
|||
cpu: [arm] |
|||
os: [linux] |
|||
|
|||
'@rollup/[email protected]': |
|||
resolution: {integrity: sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==} |
|||
'@rollup/[email protected]9.1': |
|||
resolution: {integrity: sha512-Z80O+taYxTQITWMjm/YqNoe9d10OX6kDh8X5/rFCMuPqsKsSyDilvfg+vd3iXIqtfmp+cnfL1UrYirkaF8SBZA==} |
|||
cpu: [arm64] |
|||
os: [linux] |
|||
|
|||
'@rollup/[email protected]4.0': |
|||
resolution: {integrity: sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==} |
|||
'@rollup/[email protected]9.1': |
|||
resolution: {integrity: sha512-fOHRtF9gahwJk3QVp01a/GqS4hBEZCV1oKglVVq13kcK3NeVlS4BwIFzOHDbmKzt3i0OuHG4zfRP0YoG5OF/rA==} |
|||
cpu: [arm64] |
|||
os: [linux] |
|||
|
|||
'@rollup/[email protected]': |
|||
resolution: {integrity: sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==} |
|||
'@rollup/[email protected]': |
|||
resolution: {integrity: sha512-5a7q3tnlbcg0OodyxcAdrrCxFi0DgXJSoOuidFUzHZ2GixZXQs6Tc3CHmlvqKAmOs5eRde+JJxeIf9DonkmYkw==} |
|||
cpu: [loong64] |
|||
os: [linux] |
|||
|
|||
'@rollup/[email protected]': |
|||
resolution: {integrity: sha512-9b4Mg5Yfz6mRnlSPIdROcfw1BU22FQxmfjlp/CShWwO3LilKQuMISMTtAu/bxmmrE6A902W2cZJuzx8+gJ8e9w==} |
|||
cpu: [ppc64] |
|||
os: [linux] |
|||
|
|||
'@rollup/[email protected]': |
|||
resolution: {integrity: sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==} |
|||
'@rollup/[email protected]9.1': |
|||
resolution: {integrity: sha512-G5pn0NChlbRM8OJWpJFMX4/i8OEU538uiSv0P6roZcbpe/WfhEO+AT8SHVKfp8qhDQzaz7Q+1/ixMy7hBRidnQ==} |
|||
cpu: [riscv64] |
|||
os: [linux] |
|||
|
|||
'@rollup/[email protected]4.0': |
|||
resolution: {integrity: sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==} |
|||
'@rollup/[email protected]9.1': |
|||
resolution: {integrity: sha512-WM9lIkNdkhVwiArmLxFXpWndFGuOka4oJOZh8EP3Vb8q5lzdSCBuhjavJsw68Q9AKDGeOOIHYzYm4ZFvmWez5g==} |
|||
cpu: [s390x] |
|||
os: [linux] |
|||
|
|||
'@rollup/[email protected]4.0': |
|||
resolution: {integrity: sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==} |
|||
'@rollup/[email protected]9.1': |
|||
resolution: {integrity: sha512-87xYCwb0cPGZFoGiErT1eDcssByaLX4fc0z2nRM6eMtV9njAfEE6OW3UniAoDhX4Iq5xQVpE6qO9aJbCFumKYQ==} |
|||
cpu: [x64] |
|||
os: [linux] |
|||
|
|||
'@rollup/[email protected]4.0': |
|||
resolution: {integrity: sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==} |
|||
'@rollup/[email protected]9.1': |
|||
resolution: {integrity: sha512-xufkSNppNOdVRCEC4WKvlR1FBDyqCSCpQeMMgv9ZyXqqtKBfkw1yfGMTUTs9Qsl6WQbJnsGboWCp7pJGkeMhKA==} |
|||
cpu: [x64] |
|||
os: [linux] |
|||
|
|||
'@rollup/[email protected]4.0': |
|||
resolution: {integrity: sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==} |
|||
'@rollup/[email protected]9.1': |
|||
resolution: {integrity: sha512-F2OiJ42m77lSkizZQLuC+jiZ2cgueWQL5YC9tjo3AgaEw+KJmVxHGSyQfDUoYR9cci0lAywv2Clmckzulcq6ig==} |
|||
cpu: [arm64] |
|||
os: [win32] |
|||
|
|||
'@rollup/[email protected]4.0': |
|||
resolution: {integrity: sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==} |
|||
'@rollup/[email protected]9.1': |
|||
resolution: {integrity: sha512-rYRe5S0FcjlOBZQHgbTKNrqxCBUmgDJem/VQTCcTnA2KCabYSWQDrytOzX7avb79cAAweNmMUb/Zw18RNd4mng==} |
|||
cpu: [ia32] |
|||
os: [win32] |
|||
|
|||
'@rollup/[email protected]4.0': |
|||
resolution: {integrity: sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==} |
|||
'@rollup/[email protected]9.1': |
|||
resolution: {integrity: sha512-+10CMg9vt1MoHj6x1pxyjPSMjHTIlqs8/tBztXvPAx24SKs9jwVnKqHJumlH/IzhaPUaj3T6T6wfZr8okdXaIg==} |
|||
cpu: [x64] |
|||
os: [win32] |
|||
|
|||
@ -1690,6 +1711,9 @@ packages: |
|||
'@types/[email protected]': |
|||
resolution: {integrity: sha512-RpQH4rXLuvTXKR0zqHq3go0RVXYv/YVqv4TnPH95VbwUxZdQlK1EtcMvQvMpDngHbt13Csh9Z4qT9AbkiQH5BA==} |
|||
|
|||
'@types/[email protected]': |
|||
resolution: {integrity: sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==} |
|||
|
|||
'@types/[email protected]': |
|||
resolution: {integrity: sha512-hI6cQDjw1bkJw7MC/eHMqq5TWUamLwsujnUUeiIX2KDRjxRNSYMjnHz07+LATz9I9XIsKumOtUz4gRYnZOJ/FA==} |
|||
|
|||
@ -1864,8 +1888,8 @@ packages: |
|||
resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} |
|||
engines: {node: '>= 6'} |
|||
|
|||
[email protected]38: |
|||
resolution: {integrity: sha512-5SuJUJ7cZnhPpeLHaH0c/HPAnAHZvS6ElWyHK9GSIbVOQABLzowiI2pjmpvZ1WEbkyz46iFd4UXlOHR5SqgfMQ==} |
|||
[email protected]90: |
|||
resolution: {integrity: sha512-5ExiE3qQN6oF8Clf8ifIDcMRCRE/dMGcETG/XGMD8/XiXm6HXQgQTh1yZYLXXpSOsEUlJm1Xr7kGULZTuGtP/w==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-0BJa8f4t141BYKQyn9NSQt1PguFQXMXwZiA5shfoaBYHAb2fFk2RAX+tiWMoQU+Agtzt3mdt0JtuyshAXqZ+Vw==} |
|||
@ -2417,6 +2441,10 @@ packages: |
|||
resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} |
|||
hasBin: true |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} |
|||
engines: {node: '>=14'} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} |
|||
|
|||
@ -2923,8 +2951,8 @@ packages: |
|||
rollup: |
|||
optional: true |
|||
|
|||
[email protected]4.0: |
|||
resolution: {integrity: sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==} |
|||
[email protected]9.1: |
|||
resolution: {integrity: sha512-RaJ45M/kmJUzSWDs1Nnd5DdV4eerC98idtUOVr6FfKcgxqvjwHmxc5upLF9qZU9EpsVzzhleFahrT3shLuJzIw==} |
|||
engines: {node: '>=18.0.0', npm: '>=8.0.0'} |
|||
hasBin: true |
|||
|
|||
@ -4258,68 +4286,77 @@ snapshots: |
|||
|
|||
'@radix-ui/[email protected]': {} |
|||
|
|||
'@rollup/[email protected]([email protected]4.0)': |
|||
'@rollup/[email protected]([email protected]9.1)': |
|||
dependencies: |
|||
'@rollup/pluginutils': 5.1.0([email protected]4.0) |
|||
'@rollup/pluginutils': 5.1.0([email protected]9.1) |
|||
estree-walker: 2.0.2 |
|||
magic-string: 0.30.11 |
|||
optionalDependencies: |
|||
rollup: 4.24.0 |
|||
rollup: 4.29.1 |
|||
|
|||
'@rollup/[email protected]([email protected]4.0)': |
|||
'@rollup/[email protected]([email protected]9.1)': |
|||
dependencies: |
|||
'@types/estree': 1.0.5 |
|||
estree-walker: 2.0.2 |
|||
picomatch: 2.3.1 |
|||
optionalDependencies: |
|||
rollup: 4.24.0 |
|||
rollup: 4.29.1 |
|||
|
|||
'@rollup/[email protected]': |
|||
optional: true |
|||
|
|||
'@rollup/[email protected]': |
|||
optional: true |
|||
|
|||
'@rollup/[email protected]': |
|||
optional: true |
|||
|
|||
'@rollup/[email protected]': |
|||
'@rollup/rollup-[email protected]': |
|||
optional: true |
|||
|
|||
'@rollup/[email protected]': |
|||
'@rollup/rollup-[email protected]': |
|||
optional: true |
|||
|
|||
'@rollup/[email protected]': |
|||
'@rollup/rollup-[email protected]': |
|||
optional: true |
|||
|
|||
'@rollup/rollup-[email protected]': |
|||
'@rollup/rollup-[email protected]': |
|||
optional: true |
|||
|
|||
'@rollup/rollup-linux-arm-[email protected]': |
|||
'@rollup/rollup-linux-arm-[email protected]': |
|||
optional: true |
|||
|
|||
'@rollup/rollup-linux-arm[email protected]': |
|||
'@rollup/rollup-linux-arm[email protected]': |
|||
optional: true |
|||
|
|||
'@rollup/rollup-linux-arm64-[email protected]': |
|||
'@rollup/rollup-linux-arm64-[email protected]': |
|||
optional: true |
|||
|
|||
'@rollup/rollup-linux-[email protected]': |
|||
'@rollup/rollup-linux-[email protected]': |
|||
optional: true |
|||
|
|||
'@rollup/[email protected]4.0': |
|||
'@rollup/[email protected]9.1': |
|||
optional: true |
|||
|
|||
'@rollup/[email protected]4.0': |
|||
'@rollup/[email protected]9.1': |
|||
optional: true |
|||
|
|||
'@rollup/[email protected]4.0': |
|||
'@rollup/[email protected]9.1': |
|||
optional: true |
|||
|
|||
'@rollup/[email protected]4.0': |
|||
'@rollup/[email protected]9.1': |
|||
optional: true |
|||
|
|||
'@rollup/[email protected]4.0': |
|||
'@rollup/[email protected]9.1': |
|||
optional: true |
|||
|
|||
'@rollup/[email protected]4.0': |
|||
'@rollup/[email protected]9.1': |
|||
optional: true |
|||
|
|||
'@rollup/[email protected]4.0': |
|||
'@rollup/[email protected]9.1': |
|||
optional: true |
|||
|
|||
'@rollup/[email protected]4.0': |
|||
'@rollup/[email protected]9.1': |
|||
optional: true |
|||
|
|||
'@rsbuild/[email protected]': |
|||
@ -4381,7 +4418,7 @@ snapshots: |
|||
'@module-federation/runtime-tools': 0.5.1 |
|||
'@rspack/binding': 1.0.8 |
|||
'@rspack/lite-tapable': 1.0.1 |
|||
caniuse-lite: 1.0.30001638 |
|||
caniuse-lite: 1.0.30001690 |
|||
optionalDependencies: |
|||
'@swc/helpers': 0.5.13 |
|||
|
|||
@ -5255,6 +5292,8 @@ snapshots: |
|||
|
|||
'@types/[email protected]': {} |
|||
|
|||
'@types/[email protected]': {} |
|||
|
|||
'@types/[email protected]': |
|||
dependencies: |
|||
'@types/geojson': 7946.0.14 |
|||
@ -5343,7 +5382,7 @@ snapshots: |
|||
[email protected]([email protected]): |
|||
dependencies: |
|||
browserslist: 4.23.1 |
|||
caniuse-lite: 1.0.30001638 |
|||
caniuse-lite: 1.0.30001690 |
|||
fraction.js: 4.3.7 |
|||
normalize-range: 0.1.2 |
|||
picocolors: 1.0.1 |
|||
@ -5424,7 +5463,7 @@ snapshots: |
|||
|
|||
[email protected]: |
|||
dependencies: |
|||
caniuse-lite: 1.0.30001638 |
|||
caniuse-lite: 1.0.30001690 |
|||
electron-to-chromium: 1.4.812 |
|||
node-releases: 2.0.14 |
|||
update-browserslist-db: 1.0.16([email protected]) |
|||
@ -5459,7 +5498,7 @@ snapshots: |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]38: {} |
|||
[email protected]90: {} |
|||
|
|||
[email protected]: {} |
|||
|
|||
@ -6075,6 +6114,8 @@ snapshots: |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
@ -6620,35 +6661,38 @@ snapshots: |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]([email protected]4.0): |
|||
[email protected]([email protected]9.1): |
|||
dependencies: |
|||
open: 8.4.2 |
|||
picomatch: 2.3.1 |
|||
source-map: 0.7.4 |
|||
yargs: 17.7.2 |
|||
optionalDependencies: |
|||
rollup: 4.24.0 |
|||
rollup: 4.29.1 |
|||
|
|||
[email protected]4.0: |
|||
[email protected]9.1: |
|||
dependencies: |
|||
'@types/estree': 1.0.6 |
|||
optionalDependencies: |
|||
'@rollup/rollup-android-arm-eabi': 4.24.0 |
|||
'@rollup/rollup-android-arm64': 4.24.0 |
|||
'@rollup/rollup-darwin-arm64': 4.24.0 |
|||
'@rollup/rollup-darwin-x64': 4.24.0 |
|||
'@rollup/rollup-linux-arm-gnueabihf': 4.24.0 |
|||
'@rollup/rollup-linux-arm-musleabihf': 4.24.0 |
|||
'@rollup/rollup-linux-arm64-gnu': 4.24.0 |
|||
'@rollup/rollup-linux-arm64-musl': 4.24.0 |
|||
'@rollup/rollup-linux-powerpc64le-gnu': 4.24.0 |
|||
'@rollup/rollup-linux-riscv64-gnu': 4.24.0 |
|||
'@rollup/rollup-linux-s390x-gnu': 4.24.0 |
|||
'@rollup/rollup-linux-x64-gnu': 4.24.0 |
|||
'@rollup/rollup-linux-x64-musl': 4.24.0 |
|||
'@rollup/rollup-win32-arm64-msvc': 4.24.0 |
|||
'@rollup/rollup-win32-ia32-msvc': 4.24.0 |
|||
'@rollup/rollup-win32-x64-msvc': 4.24.0 |
|||
'@rollup/rollup-android-arm-eabi': 4.29.1 |
|||
'@rollup/rollup-android-arm64': 4.29.1 |
|||
'@rollup/rollup-darwin-arm64': 4.29.1 |
|||
'@rollup/rollup-darwin-x64': 4.29.1 |
|||
'@rollup/rollup-freebsd-arm64': 4.29.1 |
|||
'@rollup/rollup-freebsd-x64': 4.29.1 |
|||
'@rollup/rollup-linux-arm-gnueabihf': 4.29.1 |
|||
'@rollup/rollup-linux-arm-musleabihf': 4.29.1 |
|||
'@rollup/rollup-linux-arm64-gnu': 4.29.1 |
|||
'@rollup/rollup-linux-arm64-musl': 4.29.1 |
|||
'@rollup/rollup-linux-loongarch64-gnu': 4.29.1 |
|||
'@rollup/rollup-linux-powerpc64le-gnu': 4.29.1 |
|||
'@rollup/rollup-linux-riscv64-gnu': 4.29.1 |
|||
'@rollup/rollup-linux-s390x-gnu': 4.29.1 |
|||
'@rollup/rollup-linux-x64-gnu': 4.29.1 |
|||
'@rollup/rollup-linux-x64-musl': 4.29.1 |
|||
'@rollup/rollup-win32-arm64-msvc': 4.29.1 |
|||
'@rollup/rollup-win32-ia32-msvc': 4.29.1 |
|||
'@rollup/rollup-win32-x64-msvc': 4.29.1 |
|||
fsevents: 2.3.3 |
|||
|
|||
[email protected]: |
|||
@ -6986,9 +7030,9 @@ snapshots: |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]([email protected]4.0)([email protected](@types/[email protected])): |
|||
[email protected]([email protected]9.1)([email protected](@types/[email protected])): |
|||
dependencies: |
|||
'@rollup/plugin-inject': 5.0.5([email protected]4.0) |
|||
'@rollup/plugin-inject': 5.0.5([email protected]9.1) |
|||
node-stdlib-browser: 1.2.0 |
|||
vite: 5.3.6(@types/[email protected]) |
|||
transitivePeerDependencies: |
|||
@ -6998,7 +7042,7 @@ snapshots: |
|||
dependencies: |
|||
esbuild: 0.21.5 |
|||
postcss: 8.4.49 |
|||
rollup: 4.24.0 |
|||
rollup: 4.29.1 |
|||
optionalDependencies: |
|||
'@types/node': 20.14.9 |
|||
fsevents: 2.3.3 |
|||
|
|||
@ -0,0 +1,134 @@ |
|||
import { useDevice } from "@app/core/stores/deviceStore"; |
|||
import { Button } from "@components/UI/Button"; |
|||
import { |
|||
Dialog, |
|||
DialogContent, |
|||
DialogDescription, |
|||
DialogFooter, |
|||
DialogHeader, |
|||
DialogTitle, |
|||
} from "@components/UI/Dialog.tsx"; |
|||
import { fromByteArray } from "base64-js"; |
|||
import { DownloadIcon, PrinterIcon } from "lucide-react"; |
|||
import React from "react"; |
|||
|
|||
export interface PkiBackupDialogProps { |
|||
open: boolean; |
|||
onOpenChange: (open: boolean) => void; |
|||
} |
|||
|
|||
export const PkiBackupDialog = ({ |
|||
open, |
|||
onOpenChange, |
|||
}: PkiBackupDialogProps) => { |
|||
const { config, setDialogOpen } = useDevice(); |
|||
const privateKey = config.security?.privateKey; |
|||
const publicKey = config.security?.publicKey; |
|||
|
|||
const decodeKeyData = React.useCallback( |
|||
(key: Uint8Array<ArrayBufferLike>) => { |
|||
if (!key) return ""; |
|||
return fromByteArray(key ?? new Uint8Array(0)); |
|||
}, |
|||
[], |
|||
); |
|||
|
|||
const closeDialog = React.useCallback(() => { |
|||
setDialogOpen("pkiBackup", false); |
|||
}, [setDialogOpen]); |
|||
|
|||
const renderPrintWindow = React.useCallback(() => { |
|||
if (!privateKey || !publicKey) return; |
|||
|
|||
const printWindow = window.open("", "_blank"); |
|||
if (printWindow) { |
|||
printWindow.document.write(` |
|||
<html> |
|||
<head> |
|||
<title>=== MESHTASTIC KEYS ===</title> |
|||
<style> |
|||
body { font-family: Arial, sans-serif; padding: 20px; } |
|||
h1 { font-size: 18px; } |
|||
p { font-size: 14px; word-break: break-all; } |
|||
</style> |
|||
</head> |
|||
<body> |
|||
<h1>=== MESHTASTIC KEYS ===</h1> |
|||
<br> |
|||
<h2>Public Key:</h2> |
|||
<p>${decodeKeyData(publicKey)}</p> |
|||
<h2>Private Key:</h2> |
|||
<p>${decodeKeyData(privateKey)}</p> |
|||
<br> |
|||
<p>=== END OF KEYS ===</p> |
|||
</body> |
|||
</html> |
|||
`);
|
|||
printWindow.document.close(); |
|||
printWindow.print(); |
|||
closeDialog(); |
|||
} |
|||
}, [decodeKeyData, privateKey, publicKey, closeDialog]); |
|||
|
|||
const createDownloadKeyFile = React.useCallback(() => { |
|||
if (!privateKey || !publicKey) return; |
|||
|
|||
const decodedPrivateKey = decodeKeyData(privateKey); |
|||
const decodedPublicKey = decodeKeyData(publicKey); |
|||
|
|||
const formattedContent = [ |
|||
"=== MESHTASTIC KEYS ===\n\n", |
|||
"Private Key:\n", |
|||
decodedPrivateKey, |
|||
"\n\nPublic Key:\n", |
|||
decodedPublicKey, |
|||
"\n\n=== END OF KEYS ===", |
|||
].join(""); |
|||
|
|||
const blob = new Blob([formattedContent], { type: "text/plain" }); |
|||
const url = URL.createObjectURL(blob); |
|||
|
|||
const link = document.createElement("a"); |
|||
link.href = url; |
|||
link.download = "meshtastic_keys.txt"; |
|||
link.style.display = "none"; |
|||
document.body.appendChild(link); |
|||
link.click(); |
|||
document.body.removeChild(link); |
|||
closeDialog(); |
|||
URL.revokeObjectURL(url); |
|||
}, [decodeKeyData, privateKey, publicKey, closeDialog]); |
|||
|
|||
return ( |
|||
<Dialog open={open} onOpenChange={onOpenChange}> |
|||
<DialogContent> |
|||
<DialogHeader> |
|||
<DialogTitle>Backup Keys</DialogTitle> |
|||
<DialogDescription> |
|||
Its important to backup your public and private keys and store your |
|||
backup securely! |
|||
</DialogDescription> |
|||
<DialogDescription> |
|||
<span className="font-bold break-before-auto"> |
|||
If you lose your keys, you will need to reset your device. |
|||
</span> |
|||
</DialogDescription> |
|||
</DialogHeader> |
|||
<DialogFooter className="mt-6"> |
|||
<Button |
|||
variant={"default"} |
|||
onClick={() => createDownloadKeyFile()} |
|||
className="" |
|||
> |
|||
<DownloadIcon size={20} className="mr-2" /> |
|||
Download |
|||
</Button> |
|||
<Button variant={"default"} onClick={() => renderPrintWindow()}> |
|||
<PrinterIcon size={20} className="mr-2" /> |
|||
Print |
|||
</Button> |
|||
</DialogFooter> |
|||
</DialogContent> |
|||
</Dialog> |
|||
); |
|||
}; |
|||
@ -0,0 +1,19 @@ |
|||
import { useBackupReminder } from "@app/core/hooks/useKeyBackupReminder"; |
|||
import { useDevice } from "@app/core/stores/deviceStore"; |
|||
|
|||
export const KeyBackupReminder = (): JSX.Element => { |
|||
const { setDialogOpen } = useDevice(); |
|||
|
|||
useBackupReminder({ |
|||
reminderInDays: 7, |
|||
message: |
|||
"We recommend backing up your key data regularly. Would you like to back up now?", |
|||
onAccept: () => setDialogOpen("pkiBackup", true), |
|||
enabled: true, |
|||
cookieOptions: { |
|||
secure: true, |
|||
sameSite: "strict", |
|||
}, |
|||
}); |
|||
return <></>; |
|||
}; |
|||
@ -0,0 +1,52 @@ |
|||
import Cookies, { type CookieAttributes } from "js-cookie"; |
|||
import { useCallback, useState } from "react"; |
|||
|
|||
interface CookieHookResult<T> { |
|||
value: T | undefined; |
|||
setCookie: (value: T, options?: CookieAttributes) => void; |
|||
removeCookie: () => void; |
|||
} |
|||
|
|||
function useCookie<T extends object>( |
|||
cookieName: string, |
|||
initialValue?: T, |
|||
): CookieHookResult<T> { |
|||
const [cookieValue, setCookieValue] = useState<T | undefined>(() => { |
|||
try { |
|||
const cookie = Cookies.get(cookieName); |
|||
return cookie ? (JSON.parse(cookie) as T) : initialValue; |
|||
} catch (error) { |
|||
console.error(`Error parsing cookie ${cookieName}:`, error); |
|||
return initialValue; |
|||
} |
|||
}); |
|||
|
|||
const setCookie = useCallback( |
|||
(value: T, options?: CookieAttributes) => { |
|||
try { |
|||
Cookies.set(cookieName, JSON.stringify(value), options); |
|||
setCookieValue(value); |
|||
} catch (error) { |
|||
console.error(`Error setting cookie ${cookieName}:`, error); |
|||
} |
|||
}, |
|||
[cookieName], |
|||
); |
|||
|
|||
const removeCookie = useCallback(() => { |
|||
try { |
|||
Cookies.remove(cookieName); |
|||
setCookieValue(undefined); |
|||
} catch (error) { |
|||
console.error(`Error removing cookie ${cookieName}:`, error); |
|||
} |
|||
}, [cookieName]); |
|||
|
|||
return { |
|||
value: cookieValue, |
|||
setCookie, |
|||
removeCookie, |
|||
}; |
|||
} |
|||
|
|||
export default useCookie; |
|||
@ -0,0 +1,120 @@ |
|||
import { Button } from "@app/components/UI/Button"; |
|||
import type { CookieAttributes } from "js-cookie"; |
|||
import { useCallback, useEffect, useRef } from "react"; |
|||
import useCookie from "./useCookie"; |
|||
import { useToast } from "./useToast"; |
|||
|
|||
interface UseBackupReminderOptions { |
|||
reminderInDays?: number; |
|||
message: string; |
|||
onAccept?: () => void | Promise<void>; |
|||
enabled: boolean; |
|||
cookieOptions?: CookieAttributes; |
|||
} |
|||
|
|||
interface ReminderState { |
|||
suppressed: boolean; |
|||
lastShown: string; |
|||
} |
|||
|
|||
const TOAST_APPEAR_DELAY = 10_000 // 10 seconds;
|
|||
const TOAST_DURATION = 30_000 // 30 seconds;:
|
|||
|
|||
// remind user in 1 year to backup keys again, if they accept the reminder;
|
|||
const ON_ACCEPT_REMINDER_DAYS = 365 |
|||
|
|||
function isReminderExpired(lastShown: string): boolean { |
|||
const lastShownDate = new Date(lastShown); |
|||
const now = new Date(); |
|||
const daysSinceLastShown = |
|||
(now.getTime() - lastShownDate.getTime()) / (1000 * 60 * 60 * 24); |
|||
return daysSinceLastShown >= 7; |
|||
} |
|||
|
|||
export function useBackupReminder({ |
|||
reminderInDays = 7, |
|||
enabled, |
|||
message, |
|||
onAccept = () => { }, |
|||
cookieOptions, |
|||
}: UseBackupReminderOptions) { |
|||
const { toast } = useToast(); |
|||
const toastShownRef = useRef(false); |
|||
const { value: reminderCookie, setCookie } = |
|||
useCookie<ReminderState>("key_backup_reminder"); |
|||
|
|||
const suppressReminder = useCallback( |
|||
(days: number) => { |
|||
const expiryDate = new Date(); |
|||
expiryDate.setDate(expiryDate.getDate() + days); |
|||
|
|||
setCookie( |
|||
{ |
|||
suppressed: true, |
|||
lastShown: new Date().toISOString(), |
|||
}, |
|||
{ ...cookieOptions, expires: expiryDate }, |
|||
); |
|||
}, |
|||
[setCookie, cookieOptions], |
|||
); |
|||
|
|||
useEffect(() => { |
|||
if (!enabled || toastShownRef.current) return; |
|||
|
|||
const shouldShowReminder = |
|||
!reminderCookie?.suppressed || |
|||
isReminderExpired(reminderCookie.lastShown); |
|||
if (!shouldShowReminder) return; |
|||
|
|||
toastShownRef.current = true; |
|||
|
|||
const { dismiss } = toast( |
|||
{ |
|||
title: "Backup Reminder", |
|||
duration: TOAST_DURATION, |
|||
delay: TOAST_APPEAR_DELAY, |
|||
description: message, |
|||
action: ( |
|||
<div className="flex gap-2"> |
|||
<Button |
|||
type="button" |
|||
variant="default" |
|||
onClick={() => { |
|||
onAccept(); |
|||
dismiss(); |
|||
suppressReminder(ON_ACCEPT_REMINDER_DAYS); |
|||
}} |
|||
> |
|||
Back up now |
|||
</Button> |
|||
<Button |
|||
type="button" |
|||
variant="outline" |
|||
onClick={() => { |
|||
dismiss(); |
|||
suppressReminder(reminderInDays); |
|||
}} |
|||
> |
|||
Remind me in {reminderInDays} days |
|||
</Button> |
|||
</div> |
|||
), |
|||
}, |
|||
); |
|||
|
|||
return () => { |
|||
if (!toastShownRef.current) { |
|||
dismiss(); |
|||
} |
|||
}; |
|||
}, [ |
|||
enabled, |
|||
message, |
|||
onAccept, |
|||
reminderInDays, |
|||
suppressReminder, |
|||
toast, |
|||
reminderCookie, |
|||
]); |
|||
} |
|||
Loading…
Reference in new issue