committed by
GitHub
25 changed files with 680 additions and 165 deletions
@ -15,8 +15,11 @@ importers: |
|||
specifier: ^0.5.2 |
|||
version: 0.5.2 |
|||
'@meshtastic/js': |
|||
specifier: 2.3.7-0 |
|||
version: 2.3.7-0 |
|||
specifier: 2.3.7-1 |
|||
version: 2.3.7-1 |
|||
'@noble/curves': |
|||
specifier: ^1.5.0 |
|||
version: 1.5.0 |
|||
'@radix-ui/react-accordion': |
|||
specifier: ^1.2.0 |
|||
version: 1.2.0(@types/[email protected])(@types/[email protected])([email protected]([email protected]))([email protected]) |
|||
@ -90,8 +93,8 @@ importers: |
|||
specifier: ^0.363.0 |
|||
version: 0.363.0([email protected]) |
|||
mapbox-gl: |
|||
specifier: npm:empty-npm-package@^1.0.0 |
|||
version: [email protected].0 |
|||
specifier: ^3.6.0 |
|||
version: 3.6.0 |
|||
maplibre-gl: |
|||
specifier: 4.1.2 |
|||
version: 4.1.2 |
|||
@ -106,7 +109,7 @@ importers: |
|||
version: 7.52.0([email protected]) |
|||
react-map-gl: |
|||
specifier: 7.1.7 |
|||
version: 7.1.7([email protected].0)([email protected])([email protected]([email protected]))([email protected]) |
|||
version: 7.1.7([email protected].0)([email protected])([email protected]([email protected]))([email protected]) |
|||
react-qrcode-logo: |
|||
specifier: ^2.10.0 |
|||
version: 2.10.0([email protected]([email protected]))([email protected]) |
|||
@ -130,8 +133,8 @@ importers: |
|||
specifier: ^1.8.2 |
|||
version: 1.8.2 |
|||
'@buf/meshtastic_protobufs.bufbuild_es': |
|||
specifier: 1.10.0-20240613143006-244927bc441a.1 |
|||
version: 1.10.0-20240613143006-244927bc441a.1(@bufbuild/[email protected]) |
|||
specifier: 1.10.0-20240906232734-3da561588c55.1 |
|||
version: 1.10.0-20240906232734-3da561588c55.1(@bufbuild/[email protected]) |
|||
'@types/chrome': |
|||
specifier: ^0.0.263 |
|||
version: 0.0.263 |
|||
@ -354,8 +357,8 @@ packages: |
|||
cpu: [x64] |
|||
os: [win32] |
|||
|
|||
'@buf/[email protected]613143006-244927bc441a.1': |
|||
resolution: {tarball: https://buf.build/gen/npm/v1/@buf/meshtastic_protobufs.bufbuild_es/-/meshtastic_protobufs.bufbuild_es-1.10.0-20240613143006-244927bc441a.1.tgz} |
|||
'@buf/[email protected]906232734-3da561588c55.1': |
|||
resolution: {tarball: https://buf.build/gen/npm/v1/@buf/meshtastic_protobufs.bufbuild_es/-/meshtastic_protobufs.bufbuild_es-1.10.0-20240906232734-3da561588c55.1.tgz} |
|||
peerDependencies: |
|||
'@bufbuild/protobuf': ^1.10.0 |
|||
|
|||
@ -557,6 +560,9 @@ packages: |
|||
resolution: {integrity: sha512-rY0o9A5ECsTQRVhv7tL/OyDpGAoUB4tTvLiW1DSzQGq4bvTPhNw1VpSNjDJc5GFZ2XuyOtSWSVN05qOtcD71qQ==} |
|||
engines: {node: '>= 0.6'} |
|||
|
|||
'@mapbox/[email protected]': |
|||
resolution: {integrity: sha512-2XghOwu16ZwPJLOFVuIOaLbN0iKMn867evzXFyf0P22dqugezfJwLmdanAgU25ITvz1TvOfVP4jsDImlDJzcWg==} |
|||
|
|||
'@mapbox/[email protected]': |
|||
resolution: {integrity: sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ==} |
|||
|
|||
@ -581,8 +587,15 @@ packages: |
|||
resolution: {integrity: sha512-eSiQ3E5LUSxAOY9ABXGyfNhout2iEa6mUxKeaQ9nJ8NL1NuaQYU7zKqzx/LEYcXe1neT4uYAgM1wYZj3fTSXtA==} |
|||
hasBin: true |
|||
|
|||
'@meshtastic/[email protected]': |
|||
resolution: {integrity: sha512-XTNyUXj3SWQ91XqwgrTZT7rTQsiI3d8noRaxnpxRw6Ck7WtjjPF0ygnPA8eQ6kastyUkgpXzcjtD9a6Qz6n+WQ==} |
|||
'@meshtastic/[email protected]': |
|||
resolution: {integrity: sha512-pv+Xk6HkKrScCrQp31k5QOUYozabXn6NhXN7c7Cc9ysG94U1wGtfueRbEbFxXCHO3JshNz0CdE1FcSMnrLMjsQ==} |
|||
|
|||
'@noble/[email protected]': |
|||
resolution: {integrity: sha512-J5EKamIHnKPyClwVrzmaf5wSdQXgdHcPZIZLu3bwnbeCx8/7NPK5q2ZBWF+5FvYGByjiQQsJYX6jfgB2wDPn3A==} |
|||
|
|||
'@noble/[email protected]': |
|||
resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} |
|||
engines: {node: '>= 16'} |
|||
|
|||
'@nodelib/[email protected]': |
|||
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} |
|||
@ -1823,6 +1836,9 @@ packages: |
|||
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} |
|||
engines: {node: '>=4'} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-0BJa8f4t141BYKQyn9NSQt1PguFQXMXwZiA5shfoaBYHAb2fFk2RAX+tiWMoQU+Agtzt3mdt0JtuyshAXqZ+Vw==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} |
|||
engines: {node: '>= 8.10.0'} |
|||
@ -1908,6 +1924,9 @@ packages: |
|||
resolution: {integrity: sha512-KWjTXWwxFd6a94m5CdRGW/t82Tr8DoBc9dNnPCAbFI1EBweN6v1tv8y4Y1m7ndkp/nkIBRxUxAzpaBnR2k3bcQ==} |
|||
engines: {node: '>=14.16'} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-umPSgYwZkdFoUrH5hIq5kf0wPSXiro51nPw0j2K/c83KflkPSTBGMz6NJvMB+07VlL0y7VPo6QJcDjcgKTTm3w==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} |
|||
engines: {node: '>=4'} |
|||
@ -1975,6 +1994,9 @@ packages: |
|||
[email protected]: |
|||
resolution: {integrity: sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} |
|||
|
|||
@ -1987,9 +2009,6 @@ packages: |
|||
[email protected]: |
|||
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-q4Mq/+XO7UNDdMiPpR/LIBIW1Zl4V0Z6UT9aKGqIAnBCtCb3lvZJM1KbDbdzdC8fKflwflModfjR29Nt0EpcwA==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} |
|||
|
|||
@ -2032,6 +2051,9 @@ packages: |
|||
[email protected]: |
|||
resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} |
|||
engines: {node: '>=8'} |
|||
@ -2074,6 +2096,9 @@ packages: |
|||
[email protected]: |
|||
resolution: {integrity: sha512-EvGQQi/zPrDA6zr6BnJD/YhwAkBP8nnJ9emh3EnHQKVMfg/MRVtPbMYdgVy/IaEmn4UfagD2a6fafPDL5hbtwg==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} |
|||
engines: {node: 6.* || 8.* || >= 10.*} |
|||
@ -2121,6 +2146,9 @@ packages: |
|||
[email protected]: |
|||
resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-qwYQr7GWBXIm9Cdzud+tyM/s9N+QFzGDZoF9YR8RYJbDKOYowzjMDPEinFtm78EQeeYMC/FJW2FXY0bHkyUgsA==} |
|||
engines: {node: '>=14'} |
|||
@ -2361,6 +2389,9 @@ packages: |
|||
peerDependencies: |
|||
react: ^16.5.1 || ^17.0.0 || ^18.0.0 |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-xjYHHIJDh6haYcKY+/9jh1eywwYfIOWCgT5Fowj4JriZexx/oOtg2S7BQDMZtpFyg9IN4VLCysmUWxY0pFNRWA==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-98T+3BesL4w/N39q/rgs9q6HzHLG6pgbS9UaTqg6fMISfzy2WGKokjK205ENFDDmEljj54/LTfdXgqg2XfYU4A==} |
|||
engines: {node: '>=16.14.0', npm: '>=8.1.0'} |
|||
@ -2575,6 +2606,9 @@ packages: |
|||
[email protected]: |
|||
resolution: {integrity: sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-1XGObUh7RN5b58vKuAsrlfqT+Rc4vmw8N4pP9gFCq1GFlTdV0Ex/D2Ro1Drvrqj++HPi3ig0Np17XPslELeMRA==} |
|||
|
|||
@ -2748,6 +2782,10 @@ packages: |
|||
resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} |
|||
hasBin: true |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-owllqNuDDEimQat7EPG0tH7JjO090xKNzUtYz6X+Sk2BXDnOCilDdNLwjWeFywG9xkJul1ULvtUQa9O4pUaY0w==} |
|||
engines: {node: '>=4.0.0'} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} |
|||
engines: {node: '>= 0.4'} |
|||
@ -2907,6 +2945,9 @@ packages: |
|||
[email protected]: |
|||
resolution: {integrity: sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} |
|||
engines: {node: '>=4'} |
|||
@ -2936,6 +2977,9 @@ packages: |
|||
[email protected]: |
|||
resolution: {integrity: sha512-Ja03QIJlPuHt4IQ2FfGex4F4JAr8m3jpaHbFbQrgwr7s7L6U8ocrHiF3J1+wf9jzhGKxvDeaCAnGDot8OjGFyA==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-RkWD54zDlEbnN01wQPk0ANHGbdCvlJx/E8A1QxhTfCbX+ROWos1Ws2MnhOm39aUGMOh+36TjUwpDmLfmwTr1Fg==} |
|||
|
|||
[email protected]: |
|||
resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} |
|||
engines: {node: '>=12.20'} |
|||
@ -3306,7 +3350,7 @@ snapshots: |
|||
'@biomejs/[email protected]': |
|||
optional: true |
|||
|
|||
'@buf/[email protected]613143006-244927bc441a.1(@bufbuild/[email protected])': |
|||
'@buf/[email protected]906232734-3da561588c55.1(@bufbuild/[email protected])': |
|||
dependencies: |
|||
'@bufbuild/protobuf': 1.10.0 |
|||
|
|||
@ -3445,6 +3489,8 @@ snapshots: |
|||
|
|||
'@mapbox/[email protected]': {} |
|||
|
|||
'@mapbox/[email protected]': {} |
|||
|
|||
'@mapbox/[email protected]': {} |
|||
|
|||
'@mapbox/[email protected]': {} |
|||
@ -3477,7 +3523,7 @@ snapshots: |
|||
sort-object: 3.0.3 |
|||
tinyqueue: 2.0.3 |
|||
|
|||
'@meshtastic/[email protected]0': |
|||
'@meshtastic/[email protected]1': |
|||
dependencies: |
|||
crc: 4.3.2 |
|||
ste-simple-events: 3.0.11 |
|||
@ -3485,6 +3531,12 @@ snapshots: |
|||
transitivePeerDependencies: |
|||
- buffer |
|||
|
|||
'@noble/[email protected]': |
|||
dependencies: |
|||
'@noble/hashes': 1.4.0 |
|||
|
|||
'@noble/[email protected]': {} |
|||
|
|||
'@nodelib/[email protected]': |
|||
dependencies: |
|||
'@nodelib/fs.stat': 2.0.5 |
|||
@ -5221,6 +5273,8 @@ snapshots: |
|||
escape-string-regexp: 1.0.5 |
|||
supports-color: 5.5.0 |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: |
|||
dependencies: |
|||
anymatch: 3.1.3 |
|||
@ -5308,6 +5362,8 @@ snapshots: |
|||
dependencies: |
|||
type-fest: 2.19.0 |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
@ -5387,6 +5443,8 @@ snapshots: |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
@ -5395,8 +5453,6 @@ snapshots: |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: |
|||
dependencies: |
|||
once: 1.4.0 |
|||
@ -5470,6 +5526,8 @@ snapshots: |
|||
dependencies: |
|||
reusify: 1.0.4 |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: |
|||
dependencies: |
|||
to-regex-range: 5.0.1 |
|||
@ -5512,6 +5570,8 @@ snapshots: |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: |
|||
@ -5559,6 +5619,8 @@ snapshots: |
|||
dependencies: |
|||
get-intrinsic: 1.2.4 |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: |
|||
dependencies: |
|||
'@gfx/zopfli': 1.0.15 |
|||
@ -5754,6 +5816,36 @@ snapshots: |
|||
dependencies: |
|||
react: 18.3.1 |
|||
|
|||
[email protected]: |
|||
dependencies: |
|||
'@mapbox/jsonlint-lines-primitives': 2.0.2 |
|||
'@mapbox/mapbox-gl-supported': 3.0.0 |
|||
'@mapbox/point-geometry': 0.1.0 |
|||
'@mapbox/tiny-sdf': 2.0.6 |
|||
'@mapbox/unitbezier': 0.0.1 |
|||
'@mapbox/vector-tile': 1.3.1 |
|||
'@mapbox/whoots-js': 3.1.0 |
|||
'@types/geojson': 7946.0.14 |
|||
'@types/mapbox__vector-tile': 1.3.4 |
|||
cheap-ruler: 4.0.0 |
|||
csscolorparser: 1.0.3 |
|||
earcut: 3.0.0 |
|||
fflate: 0.8.2 |
|||
geojson-vt: 4.0.2 |
|||
gl-matrix: 3.4.3 |
|||
grid-index: 1.1.0 |
|||
kdbush: 4.0.2 |
|||
murmurhash-js: 1.0.0 |
|||
pbf: 3.2.1 |
|||
potpack: 2.0.0 |
|||
quickselect: 3.0.0 |
|||
rw: 1.3.3 |
|||
serialize-to-js: 3.1.2 |
|||
supercluster: 8.0.1 |
|||
tinyqueue: 3.0.0 |
|||
tweakpane: 4.0.4 |
|||
vt-pbf: 3.1.3 |
|||
|
|||
[email protected]: |
|||
dependencies: |
|||
'@mapbox/geojson-rewind': 0.5.2 |
|||
@ -5963,6 +6055,8 @@ snapshots: |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: |
|||
@ -5985,14 +6079,14 @@ snapshots: |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]([email protected].0)([email protected])([email protected]([email protected]))([email protected]): |
|||
[email protected]([email protected].0)([email protected])([email protected]([email protected]))([email protected]): |
|||
dependencies: |
|||
'@maplibre/maplibre-gl-style-spec': 19.3.3 |
|||
'@types/mapbox-gl': 3.1.0 |
|||
react: 18.3.1 |
|||
react-dom: 18.3.1([email protected]) |
|||
optionalDependencies: |
|||
mapbox-gl: [email protected].0 |
|||
mapbox-gl: 3.6.0 |
|||
maplibre-gl: 4.1.2 |
|||
|
|||
[email protected]([email protected]([email protected]))([email protected]): |
|||
@ -6153,6 +6247,8 @@ snapshots: |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: |
|||
dependencies: |
|||
define-data-property: 1.1.4 |
|||
@ -6358,6 +6454,8 @@ snapshots: |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: |
|||
@ -6380,6 +6478,8 @@ snapshots: |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
|
|||
[email protected]: {} |
|||
|
|||
@ -0,0 +1,39 @@ |
|||
import { Button } from "@components/UI/Button.js"; |
|||
import { |
|||
Dialog, |
|||
DialogContent, |
|||
DialogDescription, |
|||
DialogFooter, |
|||
DialogHeader, |
|||
DialogTitle, |
|||
} from "@components/UI/Dialog.js"; |
|||
|
|||
export interface PkiRegenerateDialogProps { |
|||
open: boolean; |
|||
onOpenChange: () => void; |
|||
onSubmit: () => void; |
|||
} |
|||
|
|||
export const PkiRegenerateDialog = ({ |
|||
open, |
|||
onOpenChange, |
|||
onSubmit, |
|||
}: PkiRegenerateDialogProps): JSX.Element => { |
|||
return ( |
|||
<Dialog open={open} onOpenChange={onOpenChange}> |
|||
<DialogContent> |
|||
<DialogHeader> |
|||
<DialogTitle>Regenerate Key pair?</DialogTitle> |
|||
<DialogDescription> |
|||
Are you sure you want to regenerate key pair? |
|||
</DialogDescription> |
|||
</DialogHeader> |
|||
<DialogFooter> |
|||
<Button variant="destructive" onClick={() => onSubmit()}> |
|||
Regenerate |
|||
</Button> |
|||
</DialogFooter> |
|||
</DialogContent> |
|||
</Dialog> |
|||
); |
|||
}; |
|||
@ -0,0 +1,237 @@ |
|||
import { PkiRegenerateDialog } from "@app/components/Dialog/PkiRegenerateDialog"; |
|||
import { DynamicForm } from "@app/components/Form/DynamicForm.js"; |
|||
import { |
|||
getX25519PrivateKey, |
|||
getX25519PublicKey, |
|||
} from "@app/core/utils/x25519"; |
|||
import type { SecurityValidation } from "@app/validation/config/security.js"; |
|||
import { useDevice } from "@core/stores/deviceStore.js"; |
|||
import { Protobuf } from "@meshtastic/js"; |
|||
import { fromByteArray, toByteArray } from "base64-js"; |
|||
import { Eye, EyeOff } from "lucide-react"; |
|||
import { useState } from "react"; |
|||
|
|||
export const Security = (): JSX.Element => { |
|||
const { config, nodes, hardware, setWorkingConfig } = useDevice(); |
|||
|
|||
const [privateKey, setPrivateKey] = useState<string>( |
|||
fromByteArray(config.security?.privateKey ?? new Uint8Array(0)), |
|||
); |
|||
const [privateKeyVisible, setPrivateKeyVisible] = useState<boolean>(false); |
|||
const [privateKeyBitCount, setPrivateKeyBitCount] = useState<number>( |
|||
config.security?.privateKey.length ?? 32, |
|||
); |
|||
const [privateKeyValidationText, setPrivateKeyValidationText] = |
|||
useState<string>(); |
|||
const [publicKey, setPublicKey] = useState<string>( |
|||
fromByteArray(config.security?.publicKey ?? new Uint8Array(0)), |
|||
); |
|||
const [adminKey, setAdminKey] = useState<string>( |
|||
fromByteArray(config.security?.adminKey[0] ?? new Uint8Array(0)), |
|||
); |
|||
const [adminKeyValidationText, setAdminKeyValidationText] = |
|||
useState<string>(); |
|||
const [dialogOpen, setDialogOpen] = useState<boolean>(false); |
|||
|
|||
const onSubmit = (data: SecurityValidation) => { |
|||
if (privateKeyValidationText || adminKeyValidationText) return; |
|||
|
|||
setWorkingConfig( |
|||
new Protobuf.Config.Config({ |
|||
payloadVariant: { |
|||
case: "security", |
|||
value: { |
|||
...data, |
|||
adminKey: [toByteArray(adminKey)], |
|||
privateKey: toByteArray(privateKey), |
|||
publicKey: toByteArray(publicKey), |
|||
}, |
|||
}, |
|||
}), |
|||
); |
|||
}; |
|||
|
|||
const validateKey = ( |
|||
input: string, |
|||
count: number, |
|||
setValidationText: ( |
|||
value: React.SetStateAction<string | undefined>, |
|||
) => void, |
|||
) => { |
|||
try { |
|||
if (input.length % 4 !== 0 || toByteArray(input).length !== count) { |
|||
setValidationText(`Please enter a valid ${count * 8} bit PSK.`); |
|||
} else { |
|||
setValidationText(undefined); |
|||
} |
|||
} catch (e) { |
|||
console.error(e); |
|||
setValidationText(`Please enter a valid ${count * 8} bit PSK.`); |
|||
} |
|||
}; |
|||
|
|||
const privateKeyClickEvent = () => { |
|||
setDialogOpen(true); |
|||
}; |
|||
|
|||
const pkiRegenerate = () => { |
|||
const privateKey = getX25519PrivateKey(); |
|||
const publicKey = getX25519PublicKey(privateKey); |
|||
|
|||
setPrivateKey(fromByteArray(privateKey)); |
|||
setPublicKey(fromByteArray(publicKey)); |
|||
validateKey( |
|||
fromByteArray(privateKey), |
|||
privateKeyBitCount, |
|||
setPrivateKeyValidationText, |
|||
); |
|||
|
|||
setDialogOpen(false); |
|||
}; |
|||
|
|||
const privateKeyInputChangeEvent = ( |
|||
e: React.ChangeEvent<HTMLInputElement>, |
|||
) => { |
|||
const privateKeyB64String = e.target.value; |
|||
setPrivateKey(privateKeyB64String); |
|||
validateKey( |
|||
privateKeyB64String, |
|||
privateKeyBitCount, |
|||
setPrivateKeyValidationText, |
|||
); |
|||
|
|||
const publicKey = getX25519PublicKey(toByteArray(privateKeyB64String)); |
|||
setPublicKey(fromByteArray(publicKey)); |
|||
}; |
|||
|
|||
const adminKeyInputChangeEvent = (e: React.ChangeEvent<HTMLInputElement>) => { |
|||
const psk = e.currentTarget?.value; |
|||
setAdminKey(psk); |
|||
validateKey(psk, privateKeyBitCount, setAdminKeyValidationText); |
|||
}; |
|||
|
|||
const privateKeySelectChangeEvent = (e: string) => { |
|||
const count = Number.parseInt(e); |
|||
setPrivateKeyBitCount(count); |
|||
validateKey(privateKey, count, setPrivateKeyValidationText); |
|||
}; |
|||
|
|||
return ( |
|||
<> |
|||
<DynamicForm<SecurityValidation> |
|||
onSubmit={onSubmit} |
|||
submitType="onChange" |
|||
defaultValues={{ |
|||
...config.security, |
|||
...{ |
|||
adminKey: adminKey, |
|||
privateKey: privateKey, |
|||
publicKey: publicKey, |
|||
adminChannelEnabled: config.security?.adminChannelEnabled ?? false, |
|||
isManaged: config.security?.isManaged ?? false, |
|||
debugLogApiEnabled: config.security?.debugLogApiEnabled ?? false, |
|||
serialEnabled: config.security?.serialEnabled ?? false, |
|||
}, |
|||
}} |
|||
fieldGroups={[ |
|||
{ |
|||
label: "Security Settings", |
|||
description: "Settings for the Security configuration", |
|||
fields: [ |
|||
{ |
|||
type: "passwordGenerator", |
|||
name: "privateKey", |
|||
label: "Private Key", |
|||
description: "Used to create a shared key with a remote device", |
|||
bits: [{ text: "256 bit", value: "32", key: "bit256" }], |
|||
validationText: privateKeyValidationText, |
|||
devicePSKBitCount: privateKeyBitCount, |
|||
inputChange: privateKeyInputChangeEvent, |
|||
selectChange: privateKeySelectChangeEvent, |
|||
hide: !privateKeyVisible, |
|||
buttonClick: privateKeyClickEvent, |
|||
properties: { |
|||
value: privateKey, |
|||
action: { |
|||
icon: privateKeyVisible ? EyeOff : Eye, |
|||
onClick: () => setPrivateKeyVisible(!privateKeyVisible), |
|||
}, |
|||
}, |
|||
}, |
|||
{ |
|||
type: "text", |
|||
name: "publicKey", |
|||
label: "Public Key", |
|||
disabled: true, |
|||
description: |
|||
"Sent out to other nodes on the mesh to allow them to compute a shared secret key", |
|||
properties: { |
|||
value: publicKey, |
|||
}, |
|||
}, |
|||
], |
|||
}, |
|||
{ |
|||
label: "Admin Settings", |
|||
description: "Settings for Admin", |
|||
fields: [ |
|||
{ |
|||
type: "toggle", |
|||
name: "adminChannelEnabled", |
|||
label: "Allow Legacy Admin", |
|||
description: |
|||
"Allow incoming device control over the insecure legacy admin channel", |
|||
}, |
|||
{ |
|||
type: "toggle", |
|||
name: "isManaged", |
|||
label: "Managed", |
|||
description: |
|||
'If true, device is considered to be "managed" by a mesh administrator via admin messages', |
|||
}, |
|||
{ |
|||
type: "text", |
|||
name: "adminKey", |
|||
label: "Admin Key", |
|||
description: |
|||
"The public key authorized to send admin messages to this node", |
|||
validationText: adminKeyValidationText, |
|||
inputChange: adminKeyInputChangeEvent, |
|||
disabledBy: [ |
|||
{ fieldName: "adminChannelEnabled", invert: true }, |
|||
], |
|||
properties: { |
|||
value: adminKey, |
|||
}, |
|||
}, |
|||
], |
|||
}, |
|||
{ |
|||
label: "Logging Settings", |
|||
description: "Settings for Logging", |
|||
fields: [ |
|||
{ |
|||
type: "toggle", |
|||
name: "debugLogApiEnabled", |
|||
label: "Enable Debug Log API", |
|||
description: |
|||
"Output live debug logging over serial, view and export position-redacted device logs over Bluetooth", |
|||
}, |
|||
{ |
|||
type: "toggle", |
|||
name: "serialEnabled", |
|||
label: "Serial Output Enabled", |
|||
description: "Serial Console over the Stream API", |
|||
}, |
|||
], |
|||
}, |
|||
]} |
|||
/> |
|||
<PkiRegenerateDialog |
|||
open={dialogOpen} |
|||
onOpenChange={() => setDialogOpen(false)} |
|||
onSubmit={() => pkiRegenerate()} |
|||
/> |
|||
</> |
|||
); |
|||
}; |
|||
@ -0,0 +1,15 @@ |
|||
import { x25519 } from "@noble/curves/ed25519"; |
|||
|
|||
export function getX25519PrivateKey(): Uint8Array { |
|||
const key = x25519.utils.randomPrivateKey(); |
|||
|
|||
key[0] &= 248; |
|||
key[31] &= 127; |
|||
key[31] |= 64; |
|||
|
|||
return key; |
|||
} |
|||
|
|||
export function getX25519PublicKey(privateKey: Uint8Array): Uint8Array { |
|||
return x25519.getPublicKey(privateKey); |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
import type { Message } from "@bufbuild/protobuf"; |
|||
import type { Protobuf } from "@meshtastic/js"; |
|||
import { IsBoolean, IsString } from "class-validator"; |
|||
|
|||
export class SecurityValidation |
|||
implements |
|||
Omit< |
|||
Protobuf.Config.Config_SecurityConfig, |
|||
keyof Message | "adminKey" | "privateKey" | "publicKey" |
|||
> |
|||
{ |
|||
@IsBoolean() |
|||
adminChannelEnabled: boolean; |
|||
|
|||
@IsString() |
|||
adminKey: string; |
|||
|
|||
@IsBoolean() |
|||
bluetoothLoggingEnabled: boolean; |
|||
|
|||
@IsBoolean() |
|||
debugLogApiEnabled: boolean; |
|||
|
|||
@IsBoolean() |
|||
isManaged: boolean; |
|||
|
|||
@IsString() |
|||
privateKey: string; |
|||
|
|||
@IsString() |
|||
publicKey: string; |
|||
|
|||
@IsBoolean() |
|||
serialEnabled: boolean; |
|||
} |
|||
Loading…
Reference in new issue