Skip to content

Commit

Permalink
Add key verification & generation
Browse files Browse the repository at this point in the history
  • Loading branch information
KomelT committed Aug 22, 2024
1 parent 66fb300 commit 02a63c2
Showing 1 changed file with 103 additions and 7 deletions.
110 changes: 103 additions & 7 deletions src/components/PageComponents/Config/Security.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ 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 cryptoRandomString from "crypto-random-string";
import { Eye, EyeOff } from "lucide-react";
import { useState } from "react";

Expand All @@ -13,15 +14,27 @@ export const Security = (): JSX.Element => {
fromByteArray(config.security?.privateKey ?? new Uint8Array(0)),
);
const [privateKeyVisible, setPrivateKeyVisible] = useState<boolean>(false);
const [privateKeyBitCount, setPrivateKeyBitCount] = useState<number>(
config.security?.privateKey.length ?? 16,
);
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 ?? new Uint8Array(0)),
);
const [adminKeyVisible, setAdminKeyVisible] = useState<boolean>(false);
const [adminKeyBitCount, setAdminKeyBitCount] = useState<number>(
config.security?.adminKey.length ?? 16,
);
const [adminKeyValidationText, setAdminKeyValidationText] =
useState<string>();

const onSubmit = (data: SecurityValidation) => {
if (privateKeyValidationText || adminKeyValidationText) return;

setWorkingConfig(
new Protobuf.Config.Config({
payloadVariant: {
Expand All @@ -36,32 +49,104 @@ export const Security = (): JSX.Element => {
}),
);
};

const clickEvent = (
setKey: (value: React.SetStateAction<string>) => void,
bitCount: number,
setValidationText: (
value: React.SetStateAction<string | undefined>,
) => void,
) => {
setKey(
btoa(
cryptoRandomString({
length: bitCount ?? 0,
type: "alphanumeric",
}),
),
);
setValidationText(undefined);
};

const validatePass = (
input: string,
count: number,
setValidationText: (
value: React.SetStateAction<string | undefined>,
) => void,
) => {
if (input.length % 4 !== 0 || toByteArray(input).length !== count) {
setValidationText(`Please enter a valid ${count * 8} bit PSK.`);
} else {
setValidationText(undefined);
}
};

const privateKeyInputChangeEvent = (
e: React.ChangeEvent<HTMLInputElement>,
) => {
const psk = e.currentTarget?.value;
setPrivateKey(psk);
validatePass(psk, privateKeyBitCount, setPrivateKeyValidationText);
};

const adminKeyInputChangeEvent = (e: React.ChangeEvent<HTMLInputElement>) => {
const psk = e.currentTarget?.value;
setAdminKey(psk);
validatePass(psk, privateKeyBitCount, setAdminKeyValidationText);
};

const privateKeySelectChangeEvent = (e: string) => {
const count = Number.parseInt(e);
setPrivateKeyBitCount(count);
validatePass(privateKey, count, setPrivateKeyValidationText);
};

const adminKeySelectChangeEvent = (e: string) => {
const count = Number.parseInt(e);
setAdminKeyBitCount(count);
validatePass(privateKey, count, setAdminKeyValidationText);
};

return (
<DynamicForm<SecurityValidation>
onSubmit={onSubmit}
defaultValues={{
...config.security,
adminKey: adminKey,
privateKey: privateKey,
publicKey: publicKey,
...{
adminKey: adminKey,
privateKey: privateKey,
publicKey: publicKey,
},
}}
fieldGroups={[
{
label: "Security Settings",
description: "Settings for the Security configuration",
fields: [
{
type: privateKeyVisible ? "text" : "password",
type: "passwordGenerator",
name: "privateKey",
label: "Private Key",
description: "Used to create a shared key with a remote device",
validationText: privateKeyValidationText,
devicePSKBitCount: privateKeyBitCount,
inputChange: privateKeyInputChangeEvent,
selectChange: privateKeySelectChangeEvent,
buttonClick: () =>
clickEvent(
setPrivateKey,
privateKeyBitCount,
setPrivateKeyValidationText,
),
disabledBy: [
{
fieldName: "adminChannelEnabled",
invert: true,
},
],
properties: {
value: privateKey,
action: {
icon: privateKeyVisible ? EyeOff : Eye,
onClick: () => setPrivateKeyVisible(!privateKeyVisible),
Expand Down Expand Up @@ -97,18 +182,29 @@ export const Security = (): JSX.Element => {
'If true, device is considered to be "managed" by a mesh administrator via admin messages',
},
{
type: adminKeyVisible ? "text" : "password",
type: "passwordGenerator",
name: "adminKey",
label: "Admin Key",
description:
"The public key authorized to send admin messages to this node",
validationText: adminKeyValidationText,
devicePSKBitCount: adminKeyBitCount,
inputChange: adminKeyInputChangeEvent,
selectChange: adminKeySelectChangeEvent,
buttonClick: () =>
clickEvent(
setAdminKey,
adminKeyBitCount,
setAdminKeyValidationText,
),
disabledBy: [{ fieldName: "adminChannelEnabled" }],
properties: {
value: adminKey,
action: {
icon: adminKeyVisible ? EyeOff : Eye,
onClick: () => setAdminKeyVisible(!adminKeyVisible),
},
},
description:
"The public key authorized to send admin messages to this node",
},
],
},
Expand Down

0 comments on commit 02a63c2

Please sign in to comment.