🐛 fix: Fixing issues with generating standard and quantum-resistant encryption keys

This commit is contained in:
web
2025-11-04 20:40:53 -08:00
parent 2182400adc
commit 5eac6a9f4a
32 changed files with 142 additions and 32 deletions
@@ -444,7 +444,16 @@ export const PROTOCOL_FIELDS: Record<string, FieldConfig[]> = {
placeholder: (t) => t('encryption_private_key_placeholder'),
group: 'encryption',
generate: {
function: generateMLKEM768KeyPair,
functions: [
{
label: (t) => t('generate_standard_encryption_key'),
function: generateRealityKeyPair,
},
{
label: (t) => t('generate_quantum_resistant_key'),
function: generateMLKEM768KeyPair,
},
],
updateFields: {
encryption_private_key: 'privateKey',
encryption_password: 'publicKey',
@@ -12,7 +12,11 @@ export type FieldConfig = {
step?: number;
suffix?: string;
generate?: {
function: () => Promise<string | Record<string, string>> | string | Record<string, string>;
function?: () => Promise<string | Record<string, string>> | string | Record<string, string>;
functions?: {
label: string | ((t: (key: string) => string, protocol: any) => string);
function: () => Promise<string | Record<string, string>> | string | Record<string, string>;
}[];
updateFields?: Record<string, string>;
};
condition?: (protocol: any, values: any) => boolean;
@@ -1,11 +1,11 @@
import * as x25519 from '@noble/ed25519';
import { x25519 } from '@noble/curves/ed25519.js';
import { toB64Url } from './util';
/**
* Generate a Reality key pair
* @returns An object containing the private and public keys in base64url format
*/
export async function generateRealityKeyPair() {
const { secretKey, publicKey } = await x25519.keygenAsync();
export function generateRealityKeyPair() {
const { secretKey, publicKey } = x25519.keygen();
return { privateKey: toB64Url(secretKey), publicKey: toB64Url(publicKey) };
}
@@ -61,7 +61,6 @@ export default function ServersPage() {
const { fetchServers } = useServer();
const [loading, setLoading] = useState(false);
const [migrating, setMigrating] = useState(false);
const ref = useRef<ProTableActions>(null);
return (
@@ -10,6 +10,12 @@ import {
} from '@workspace/ui/components/accordion';
import { Badge } from '@workspace/ui/components/badge';
import { Button } from '@workspace/ui/components/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@workspace/ui/components/dropdown-menu';
import {
Form,
FormControl,
@@ -99,29 +105,68 @@ function DynamicField({
onValueChange={(v) => fieldProps.onChange(v)}
suffix={
field.generate ? (
<Button
type='button'
variant='ghost'
onClick={async () => {
const result = await field.generate!.function();
if (typeof result === 'string') {
fieldProps.onChange(result);
} else if (field.generate!.updateFields) {
Object.entries(field.generate!.updateFields).forEach(
([fieldName, resultKey]) => {
const fullFieldName = `protocols.${protocolIndex}.${fieldName}`;
form.setValue(fullFieldName, (result as any)[resultKey]);
},
);
} else {
if (result.privateKey) {
fieldProps.onChange(result.privateKey);
field.generate.functions && field.generate.functions.length > 0 ? (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button type='button' variant='ghost' size='sm'>
<Icon icon='mdi:key' className='h-4 w-4' />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align='end'>
{field.generate.functions.map((genFunc, idx) => (
<DropdownMenuItem
key={idx}
onClick={async () => {
const result = await genFunc.function();
if (typeof result === 'string') {
fieldProps.onChange(result);
} else if (field.generate!.updateFields) {
Object.entries(field.generate!.updateFields).forEach(
([fieldName, resultKey]) => {
const fullFieldName = `protocols.${protocolIndex}.${fieldName}`;
form.setValue(fullFieldName, (result as any)[resultKey]);
},
);
} else {
if (result.privateKey) {
fieldProps.onChange(result.privateKey);
}
}
}}
>
{typeof genFunc.label === 'function'
? genFunc.label(t, protocolData)
: genFunc.label}
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
) : field.generate.function ? (
<Button
type='button'
variant='ghost'
size='sm'
onClick={async () => {
const result = await field.generate!.function!();
if (typeof result === 'string') {
fieldProps.onChange(result);
} else if (field.generate!.updateFields) {
Object.entries(field.generate!.updateFields).forEach(
([fieldName, resultKey]) => {
const fullFieldName = `protocols.${protocolIndex}.${fieldName}`;
form.setValue(fullFieldName, (result as any)[resultKey]);
},
);
} else {
if (result.privateKey) {
fieldProps.onChange(result.privateKey);
}
}
}
}}
>
<Icon icon='mdi:key' className='h-4 w-4' />
</Button>
}}
>
<Icon icon='mdi:key' className='h-4 w-4' />
</Button>
) : null
) : (
field.suffix
)