Browse Source

Channel PSK generator

pull/2/head
Sacha Weatherstone 5 years ago
parent
commit
3ac36a8a87
  1. 67
      src/components/Channel.tsx
  2. 2
      src/pages/settings/Channels.tsx

67
src/components/Channel.tsx

@ -1,13 +1,16 @@
import React from 'react'; import React from 'react';
import { useForm } from 'react-hook-form'; import { fromByteArray, toByteArray } from 'base64-js';
import { useForm, useWatch } from 'react-hook-form';
import { FaQrcode } from 'react-icons/fa'; import { FaQrcode } from 'react-icons/fa';
import { FiEdit3, FiSave } from 'react-icons/fi'; import { FiEdit3, FiSave } from 'react-icons/fi';
import { MdRefresh, MdVisibility, MdVisibilityOff } from 'react-icons/md';
import QRCode from 'react-qr-code'; import QRCode from 'react-qr-code';
import { Card } from '@components/generic/Card'; import { Card } from '@components/generic/Card';
import { Checkbox } from '@components/generic/form/Checkbox'; import { Checkbox } from '@components/generic/form/Checkbox';
import { Input } from '@components/generic/form/Input'; import { Input } from '@components/generic/form/Input';
import { Select } from '@components/generic/form/Select';
import { IconButton } from '@components/generic/IconButton'; import { IconButton } from '@components/generic/IconButton';
import { Loading } from '@components/generic/Loading'; import { Loading } from '@components/generic/Loading';
import { Modal } from '@components/generic/Modal'; import { Modal } from '@components/generic/Modal';
@ -16,18 +19,17 @@ import { Protobuf } from '@meshtastic/meshtasticjs';
export interface ChannelProps { export interface ChannelProps {
channel: Protobuf.Channel; channel: Protobuf.Channel;
hideEnabled?: boolean; isPrimary?: boolean;
} }
export const Channel = ({ export const Channel = ({ channel, isPrimary }: ChannelProps): JSX.Element => {
channel,
hideEnabled,
}: ChannelProps): JSX.Element => {
const [edit, setEdit] = React.useState(false); const [edit, setEdit] = React.useState(false);
const [loading, setLoading] = React.useState(false); const [loading, setLoading] = React.useState(false);
const [showQr, setShowQr] = React.useState(false); const [showQr, setShowQr] = React.useState(false);
const [keySize, setKeySize] = React.useState<128 | 256>(256);
const [pskHidden, setPskHidden] = React.useState(true);
const { register, handleSubmit } = useForm<{ const { register, handleSubmit, setValue, control } = useForm<{
enabled: boolean; enabled: boolean;
settings: { settings: {
name: string; name: string;
@ -55,11 +57,17 @@ export const Channel = ({
downlinkEnabled: channel.settings?.downlinkEnabled, downlinkEnabled: channel.settings?.downlinkEnabled,
uplinkEnabled: channel.settings?.uplinkEnabled, uplinkEnabled: channel.settings?.uplinkEnabled,
txPower: channel.settings?.txPower, txPower: channel.settings?.txPower,
psk: new TextDecoder().decode(channel.settings?.psk), psk: fromByteArray(channel.settings?.psk ?? new Uint8Array(0)),
}, },
}, },
}); });
const watchPsk = useWatch({
control,
name: 'settings.psk',
defaultValue: '',
});
const onSubmit = handleSubmit(async (data) => { const onSubmit = handleSubmit(async (data) => {
setLoading(true); setLoading(true);
const adminChannel = Protobuf.Channel.create({ const adminChannel = Protobuf.Channel.create({
@ -72,7 +80,7 @@ export const Channel = ({
index: channel.index, index: channel.index,
settings: { settings: {
...data.settings, ...data.settings,
psk: new TextEncoder().encode(data.settings.psk), psk: toByteArray(data.settings.psk ?? ''),
}, },
}); });
@ -91,26 +99,57 @@ export const Channel = ({
}} }}
> >
<Card> <Card>
<QRCode className="rounded-md" value="test" /> <QRCode
className="rounded-md"
value={`https://www.meshtastic.org/d/#${watchPsk}`}
/>
</Card> </Card>
</Modal> </Modal>
{edit ? ( {edit ? (
<> <>
{loading && <Loading />} {loading && <Loading />}
<div className="flex my-auto"> <div className="flex my-auto">
{/* TODO: get gap working */}
<form className="gap-3"> <form className="gap-3">
{/* @todo: change to disable & make primary buttons */} {!isPrimary && (
{!hideEnabled && (
<Checkbox <Checkbox
label="Enabled" label="Enabled"
{...register('enabled', { valueAsNumber: true })} {...register('enabled', { valueAsNumber: true })}
/> />
)} )}
<Input label="Name" {...register('settings.name')} /> <Input label="Name" {...register('settings.name')} />
<Select
label="Key Size"
options={[
{ name: '128 Bit', value: 128 },
{ name: '256 Bit', value: 256 },
]}
value={keySize}
onChange={(e): void => {
setKeySize(parseInt(e.target.value) as 128 | 256);
}}
/>
<Input <Input
label="Pre-Shared Key" label="Pre-Shared Key"
type="password" type={pskHidden ? 'password' : 'text'}
disabled
action={
<>
<IconButton
onClick={(): void => {
setPskHidden(!setPskHidden);
}}
icon={pskHidden ? <MdVisibility /> : <MdVisibilityOff />}
/>
<IconButton
onClick={(): void => {
const key = new Uint8Array(keySize);
crypto.getRandomValues(key);
setValue('settings.psk', fromByteArray(key));
}}
icon={<MdRefresh />}
/>
</>
}
{...register('settings.psk')} {...register('settings.psk')}
/> />
<Checkbox <Checkbox

2
src/pages/settings/Channels.tsx

@ -246,7 +246,7 @@ export const Channels = ({
<Channel <Channel
key={channel.channel.index} key={channel.channel.index}
channel={channel.channel} channel={channel.channel}
hideEnabled={channel.channel.index === 0} isPrimary={channel.channel.index === 0}
/> />
))} ))}

Loading…
Cancel
Save