initial working version
This commit is contained in:
@@ -3,11 +3,11 @@ import type {
|
|||||||
GenericFormElementProps,
|
GenericFormElementProps,
|
||||||
} from "@components/Form/DynamicForm.js";
|
} from "@components/Form/DynamicForm.js";
|
||||||
import { Generator } from "@components/UI/Generator.js";
|
import { Generator } from "@components/UI/Generator.js";
|
||||||
import { useState } from "react";
|
|
||||||
import { Controller, type FieldValues } from "react-hook-form";
|
import { Controller, type FieldValues } from "react-hook-form";
|
||||||
|
|
||||||
export interface PasswordGeneratorProps<T> extends BaseFormBuilderProps<T> {
|
export interface PasswordGeneratorProps<T> extends BaseFormBuilderProps<T> {
|
||||||
type: "passwordGenerator";
|
type: "passwordGenerator";
|
||||||
|
devicePSKBitCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PasswordGenerator<T extends FieldValues>({
|
export function PasswordGenerator<T extends FieldValues>({
|
||||||
@@ -20,11 +20,13 @@ export function PasswordGenerator<T extends FieldValues>({
|
|||||||
control={control}
|
control={control}
|
||||||
render={({ field: { value, onChange, ...rest } }) => (
|
render={({ field: { value, onChange, ...rest } }) => (
|
||||||
<Generator
|
<Generator
|
||||||
|
devicePSKBitCount={field.devicePSKBitCount}
|
||||||
|
changeEvent={onChange}
|
||||||
|
value={value}
|
||||||
variant={"success"}
|
variant={"success"}
|
||||||
textValue="Generate"
|
buttonText="Generate"
|
||||||
{...field.properties}
|
{...field.properties}
|
||||||
{...rest}
|
{...rest} />
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { useToast } from "@core/hooks/useToast.js";
|
|||||||
import { useDevice } from "@core/stores/deviceStore.js";
|
import { useDevice } from "@core/stores/deviceStore.js";
|
||||||
import { Protobuf } from "@meshtastic/js";
|
import { Protobuf } from "@meshtastic/js";
|
||||||
import { fromByteArray, toByteArray } from "base64-js";
|
import { fromByteArray, toByteArray } from "base64-js";
|
||||||
|
import cryptoRandomString from "crypto-random-string";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
export interface SettingsPanelProps {
|
export interface SettingsPanelProps {
|
||||||
channel: Protobuf.Channel.Channel;
|
channel: Protobuf.Channel.Channel;
|
||||||
@@ -13,12 +15,15 @@ export const Channel = ({ channel }: SettingsPanelProps): JSX.Element => {
|
|||||||
const { config, connection, addChannel } = useDevice();
|
const { config, connection, addChannel } = useDevice();
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
|
||||||
|
const [pass, setPass] = useState<string>(fromByteArray(channel?.settings?.psk ?? new Uint8Array(0)));
|
||||||
|
const [bitCount, setBits] = useState<number>(channel?.settings?.psk.length ?? 16);
|
||||||
|
|
||||||
const onSubmit = (data: ChannelValidation) => {
|
const onSubmit = (data: ChannelValidation) => {
|
||||||
const channel = new Protobuf.Channel.Channel({
|
const channel = new Protobuf.Channel.Channel({
|
||||||
...data,
|
...data,
|
||||||
settings: {
|
settings: {
|
||||||
...data.settings,
|
...data.settings,
|
||||||
psk: toByteArray(data.settings.psk ?? ""),
|
psk: toByteArray(pass),
|
||||||
moduleSettings: {
|
moduleSettings: {
|
||||||
positionPrecision: data.settings.positionEnabled
|
positionPrecision: data.settings.positionEnabled
|
||||||
? data.settings.preciseLocation
|
? data.settings.preciseLocation
|
||||||
@@ -36,6 +41,18 @@ export const Channel = ({ channel }: SettingsPanelProps): JSX.Element => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const clickEventCb = (e) => {
|
||||||
|
setPass(
|
||||||
|
btoa(
|
||||||
|
cryptoRandomString({
|
||||||
|
length: bitCount ?? 0,
|
||||||
|
type: "alphanumeric",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DynamicForm<ChannelValidation>
|
<DynamicForm<ChannelValidation>
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
@@ -46,7 +63,7 @@ export const Channel = ({ channel }: SettingsPanelProps): JSX.Element => {
|
|||||||
...{
|
...{
|
||||||
settings: {
|
settings: {
|
||||||
...channel?.settings,
|
...channel?.settings,
|
||||||
psk: fromByteArray(channel?.settings?.psk ?? new Uint8Array(0)),
|
psk: pass,
|
||||||
positionEnabled:
|
positionEnabled:
|
||||||
channel?.settings?.moduleSettings?.positionPrecision !==
|
channel?.settings?.moduleSettings?.positionPrecision !==
|
||||||
undefined &&
|
undefined &&
|
||||||
@@ -80,11 +97,11 @@ export const Channel = ({ channel }: SettingsPanelProps): JSX.Element => {
|
|||||||
name: "settings.psk",
|
name: "settings.psk",
|
||||||
label: "pre-Shared Key",
|
label: "pre-Shared Key",
|
||||||
description: "256, 128, or 8 bit PSKs allowed",
|
description: "256, 128, or 8 bit PSKs allowed",
|
||||||
|
devicePSKBitCount: bitCount ?? 0,
|
||||||
properties: {
|
properties: {
|
||||||
passwordValue: fromByteArray(
|
value: pass,
|
||||||
channel?.settings?.psk ?? new Uint8Array(0),
|
onClick: clickEventCb,
|
||||||
),
|
changeEvent: (e: string) => setBits(parseInt(e)),
|
||||||
devicePSKBitCount: channel?.settings?.psk.length,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ import {
|
|||||||
SelectTrigger,
|
SelectTrigger,
|
||||||
SelectValue,
|
SelectValue,
|
||||||
} from "@components/UI/Select.js";
|
} from "@components/UI/Select.js";
|
||||||
import { cn } from "@core/utils/cn.js";
|
|
||||||
import cryptoRandomString from "crypto-random-string";
|
import cryptoRandomString from "crypto-random-string";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { fromByteArray, toByteArray } from "base64-js";
|
||||||
|
|
||||||
const generatorVariants = cva(
|
const generatorVariants = cva(
|
||||||
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus:outline-none focus:ring-2",
|
"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus:outline-none focus:ring-2",
|
||||||
@@ -49,36 +49,41 @@ export interface GeneratorProps
|
|||||||
extends React.BaseHTMLAttributes<HTMLElement>,
|
extends React.BaseHTMLAttributes<HTMLElement>,
|
||||||
VariantProps<typeof generatorVariants> {
|
VariantProps<typeof generatorVariants> {
|
||||||
devicePSKBitCount?: number;
|
devicePSKBitCount?: number;
|
||||||
passwordValue?: string;
|
value: string;
|
||||||
textValue?: string;
|
buttonText?: string;
|
||||||
|
changeEvent: Function;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Generator = React.forwardRef<HTMLButtonElement, GeneratorProps>(
|
const getBitString = (bitcount?: number) => {
|
||||||
|
if (bitcount == 32) {
|
||||||
|
return "32"
|
||||||
|
}
|
||||||
|
if (bitcount == 1) {
|
||||||
|
return "1"
|
||||||
|
}
|
||||||
|
return "16"
|
||||||
|
}
|
||||||
|
|
||||||
|
const Generator = React.forwardRef<HTMLInputElement, GeneratorProps>(
|
||||||
(
|
(
|
||||||
{
|
{
|
||||||
devicePSKBitCount,
|
devicePSKBitCount,
|
||||||
passwordValue,
|
value,
|
||||||
textValue,
|
buttonText,
|
||||||
className,
|
|
||||||
variant,
|
variant,
|
||||||
size,
|
changeEvent,
|
||||||
...props
|
...props
|
||||||
},
|
},
|
||||||
ref,
|
ref,
|
||||||
) => {
|
) => {
|
||||||
const [pass, setPass] = useState<string>(passwordValue ?? "");
|
|
||||||
const [bitCount, setBits] = useState<string>(
|
|
||||||
devicePSKBitCount?.toString() ?? "",
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Input type="text" id="pskInput" value={pass} />
|
<Input type="text" id="pskInput" value={value} />
|
||||||
<Select
|
<Select
|
||||||
value={bitCount}
|
value={getBitString(devicePSKBitCount)}
|
||||||
onValueChange={(value) => {
|
onValueChange={(e) => changeEvent(e)}
|
||||||
setBits(value);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue />
|
<SelectValue />
|
||||||
@@ -98,20 +103,9 @@ const Generator = React.forwardRef<HTMLButtonElement, GeneratorProps>(
|
|||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
variant="success"
|
variant="success"
|
||||||
ref={ref}
|
|
||||||
{...props}
|
{...props}
|
||||||
onClick={() => {
|
|
||||||
setPass(
|
|
||||||
btoa(
|
|
||||||
cryptoRandomString({
|
|
||||||
length: Number.parseInt(bitCount),
|
|
||||||
type: "alphanumeric",
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{textValue}
|
{buttonText}
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user