Skip to content
This repository was archived by the owner on Dec 11, 2025. It is now read-only.

Commit 5eac6a9

Browse files
author
web
committed
🐛 fix: Fixing issues with generating standard and quantum-resistant encryption keys
1 parent 2182400 commit 5eac6a9

File tree

32 files changed

+142
-32
lines changed

32 files changed

+142
-32
lines changed

CHANGELOG.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
<a name="readme-top"></a>
2+
23
# Changelog
34

45
# [1.6.0](https://github.com/perfect-panel/ppanel-web/compare/v1.5.4...v1.6.0) (2025-10-28)
56

6-
77
### ✨ Features
88

9-
* Add server installation dialog and commands ([4429c9d](https://github.com/perfect-panel/ppanel-web/commit/4429c9d))
10-
9+
- Add server installation dialog and commands ([4429c9d](https://github.com/perfect-panel/ppanel-web/commit/4429c9d))
1110

1211
### 🐛 Bug Fixes
1312

14-
* Add typeRoots configuration to ensure type definitions are resolved correctly ([ad60ea9](https://github.com/perfect-panel/ppanel-web/commit/ad60ea9))
13+
- Add typeRoots configuration to ensure type definitions are resolved correctly ([ad60ea9](https://github.com/perfect-panel/ppanel-web/commit/ad60ea9))
1514

1615
<a name="readme-top"></a>
1716

apps/admin/app/dashboard/servers/form-schema/fields.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,7 +444,16 @@ export const PROTOCOL_FIELDS: Record<string, FieldConfig[]> = {
444444
placeholder: (t) => t('encryption_private_key_placeholder'),
445445
group: 'encryption',
446446
generate: {
447-
function: generateMLKEM768KeyPair,
447+
functions: [
448+
{
449+
label: (t) => t('generate_standard_encryption_key'),
450+
function: generateRealityKeyPair,
451+
},
452+
{
453+
label: (t) => t('generate_quantum_resistant_key'),
454+
function: generateMLKEM768KeyPair,
455+
},
456+
],
448457
updateFields: {
449458
encryption_private_key: 'privateKey',
450459
encryption_password: 'publicKey',

apps/admin/app/dashboard/servers/form-schema/types.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ export type FieldConfig = {
1212
step?: number;
1313
suffix?: string;
1414
generate?: {
15-
function: () => Promise<string | Record<string, string>> | string | Record<string, string>;
15+
function?: () => Promise<string | Record<string, string>> | string | Record<string, string>;
16+
functions?: {
17+
label: string | ((t: (key: string) => string, protocol: any) => string);
18+
function: () => Promise<string | Record<string, string>> | string | Record<string, string>;
19+
}[];
1620
updateFields?: Record<string, string>;
1721
};
1822
condition?: (protocol: any, values: any) => boolean;
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import * as x25519 from '@noble/ed25519';
1+
import { x25519 } from '@noble/curves/ed25519.js';
22
import { toB64Url } from './util';
33

44
/**
55
* Generate a Reality key pair
66
* @returns An object containing the private and public keys in base64url format
77
*/
8-
export async function generateRealityKeyPair() {
9-
const { secretKey, publicKey } = await x25519.keygenAsync();
8+
export function generateRealityKeyPair() {
9+
const { secretKey, publicKey } = x25519.keygen();
1010
return { privateKey: toB64Url(secretKey), publicKey: toB64Url(publicKey) };
1111
}

apps/admin/app/dashboard/servers/page.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ export default function ServersPage() {
6161
const { fetchServers } = useServer();
6262

6363
const [loading, setLoading] = useState(false);
64-
const [migrating, setMigrating] = useState(false);
6564
const ref = useRef<ProTableActions>(null);
6665

6766
return (

apps/admin/app/dashboard/servers/server-form.tsx

Lines changed: 67 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ import {
1010
} from '@workspace/ui/components/accordion';
1111
import { Badge } from '@workspace/ui/components/badge';
1212
import { Button } from '@workspace/ui/components/button';
13+
import {
14+
DropdownMenu,
15+
DropdownMenuContent,
16+
DropdownMenuItem,
17+
DropdownMenuTrigger,
18+
} from '@workspace/ui/components/dropdown-menu';
1319
import {
1420
Form,
1521
FormControl,
@@ -99,29 +105,68 @@ function DynamicField({
99105
onValueChange={(v) => fieldProps.onChange(v)}
100106
suffix={
101107
field.generate ? (
102-
<Button
103-
type='button'
104-
variant='ghost'
105-
onClick={async () => {
106-
const result = await field.generate!.function();
107-
if (typeof result === 'string') {
108-
fieldProps.onChange(result);
109-
} else if (field.generate!.updateFields) {
110-
Object.entries(field.generate!.updateFields).forEach(
111-
([fieldName, resultKey]) => {
112-
const fullFieldName = `protocols.${protocolIndex}.${fieldName}`;
113-
form.setValue(fullFieldName, (result as any)[resultKey]);
114-
},
115-
);
116-
} else {
117-
if (result.privateKey) {
118-
fieldProps.onChange(result.privateKey);
108+
field.generate.functions && field.generate.functions.length > 0 ? (
109+
<DropdownMenu>
110+
<DropdownMenuTrigger asChild>
111+
<Button type='button' variant='ghost' size='sm'>
112+
<Icon icon='mdi:key' className='h-4 w-4' />
113+
</Button>
114+
</DropdownMenuTrigger>
115+
<DropdownMenuContent align='end'>
116+
{field.generate.functions.map((genFunc, idx) => (
117+
<DropdownMenuItem
118+
key={idx}
119+
onClick={async () => {
120+
const result = await genFunc.function();
121+
if (typeof result === 'string') {
122+
fieldProps.onChange(result);
123+
} else if (field.generate!.updateFields) {
124+
Object.entries(field.generate!.updateFields).forEach(
125+
([fieldName, resultKey]) => {
126+
const fullFieldName = `protocols.${protocolIndex}.${fieldName}`;
127+
form.setValue(fullFieldName, (result as any)[resultKey]);
128+
},
129+
);
130+
} else {
131+
if (result.privateKey) {
132+
fieldProps.onChange(result.privateKey);
133+
}
134+
}
135+
}}
136+
>
137+
{typeof genFunc.label === 'function'
138+
? genFunc.label(t, protocolData)
139+
: genFunc.label}
140+
</DropdownMenuItem>
141+
))}
142+
</DropdownMenuContent>
143+
</DropdownMenu>
144+
) : field.generate.function ? (
145+
<Button
146+
type='button'
147+
variant='ghost'
148+
size='sm'
149+
onClick={async () => {
150+
const result = await field.generate!.function!();
151+
if (typeof result === 'string') {
152+
fieldProps.onChange(result);
153+
} else if (field.generate!.updateFields) {
154+
Object.entries(field.generate!.updateFields).forEach(
155+
([fieldName, resultKey]) => {
156+
const fullFieldName = `protocols.${protocolIndex}.${fieldName}`;
157+
form.setValue(fullFieldName, (result as any)[resultKey]);
158+
},
159+
);
160+
} else {
161+
if (result.privateKey) {
162+
fieldProps.onChange(result.privateKey);
163+
}
119164
}
120-
}
121-
}}
122-
>
123-
<Icon icon='mdi:key' className='h-4 w-4' />
124-
</Button>
165+
}}
166+
>
167+
<Icon icon='mdi:key' className='h-4 w-4' />
168+
</Button>
169+
) : null
125170
) : (
126171
field.suffix
127172
)

apps/admin/locales/cs-CZ/servers.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
"expired": "Vypršelo",
5151
"extra": "Další konfigurace",
5252
"flow": "Tok",
53+
"generate_quantum_resistant_key": "Generovat kvantově odolný klíč",
54+
"generate_standard_encryption_key": "Generovat standardní šifrovací klíč",
5355
"hop_interval": "Interval skoku",
5456
"hop_ports": "Porty skoku",
5557
"hop_ports_placeholder": "např. 1-65535",

apps/admin/locales/de-DE/servers.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
"expired": "Abgelaufen",
5151
"extra": "Zusätzliche Konfiguration",
5252
"flow": "Fluss",
53+
"generate_quantum_resistant_key": "Quantenresistenten Schlüssel generieren",
54+
"generate_standard_encryption_key": "Standard-Verschlüsselungsschlüssel generieren",
5355
"hop_interval": "Hop-Intervall",
5456
"hop_ports": "Hop-Ports",
5557
"hop_ports_placeholder": "z.B. 1-65535",

apps/admin/locales/en-US/servers.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
"expired": "Expired",
5151
"extra": "Extra Configuration",
5252
"flow": "Flow",
53+
"generate_quantum_resistant_key": "Generate Quantum-Resistant Key",
54+
"generate_standard_encryption_key": "Generate Standard Encryption Key",
5355
"hop_interval": "Hop interval",
5456
"hop_ports": "Hop ports",
5557
"hop_ports_placeholder": "e.g. 1-65535",

apps/admin/locales/es-ES/servers.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
"expired": "Expirado",
5151
"extra": "Configuración Extra",
5252
"flow": "Flujo",
53+
"generate_quantum_resistant_key": "Generar clave resistente a cuánticos",
54+
"generate_standard_encryption_key": "Generar clave de cifrado estándar",
5355
"hop_interval": "Intervalo de salto",
5456
"hop_ports": "Puertos de salto",
5557
"hop_ports_placeholder": "p. ej. 1-65535",

0 commit comments

Comments
 (0)