fix(web): align central network initial-node protocols (#2704)

This commit is contained in:
KKRainbow authored and GitHub committed 2026-10-15 01:30:06 +08:00
1 parent 8839b4b2f1
commit ec694f7cb8
5 files changed
+82 -27

No files matched your search

@@ -10,6 +10,7 @@ import {
formFlags,
NetworkConfig,
normalizeNetworkConfig,
PEER_PROTOCOLS as protos,
removeRow,
} from '../types/network'
import { computed, ref, onMounted, onUnmounted, watch } from 'vue'
@@ -84,20 +85,6 @@ const secureModeEnabled = computed({
const { t } = useI18n()
const protos: { [proto: string]: number } = {
tcp: 11010,
udp: 11010,
wg: 11011,
ws: 11011,
wss: 11012,
quic: 11012,
faketcp: 11013,
http: 80,
https: 443,
txt: 0,
srv: 0,
}
const listenerExcludedProtos = new Set(['http', 'https', 'txt', 'srv'])
const listenerProtos: { [proto: string]: number } = Object.fromEntries(
Object.entries(protos).filter(([proto]) => !listenerExcludedProtos.has(proto))
@@ -41,6 +41,20 @@ export { AclAction, AclChainType, AclProtocol, CompressionAlgoPb, NatType, Netwo
export { VpnPortalClientState }
export type { Acl, AclChain, AclRule, AclV1, GroupIdentity, GroupInfo, NetworkPeerConfig, PeerFeatureFlag, PortForwardConfig, SecureModeConfig, VpnPortalClientConfig, VpnPortalClientInfo, VpnPortalConfig, VpnPortalInfo }
export const PEER_PROTOCOLS: { [proto: string]: number } = {
tcp: 11010,
udp: 11010,
wg: 11011,
ws: 11011,
wss: 11012,
quic: 11012,
faketcp: 11013,
http: 80,
https: 443,
txt: 0,
srv: 0,
}
export type NetworkConfig = Omit<
ProtoNetworkConfig,
| 'instance_id'
@@ -302,12 +302,7 @@ const savingSettings = ref(false);
const gatewayInfo = ref<{ enabled: boolean; peer_url?: string } | undefined>(undefined);
const protos: { [proto: string]: number } = {
tcp: 11010,
udp: 11010,
ws: 11011,
wss: 11012,
};
const protos = NetworkTypes.PEER_PROTOCOLS;
const gatewayFollowed = () =>
gatewayInfo.value?.enabled === true
@@ -3,7 +3,7 @@ import { computed, onMounted, onUnmounted, ref } from 'vue';
import { Button, Column, DataTable, Dialog, InputSwitch, InputText, Message, Skeleton, Tag, useToast } from 'primevue';
import { useRoute, useRouter } from 'vue-router';
import { useI18n } from 'vue-i18n';
import { UrlListInput, Utils } from 'easytier-frontend-lib';
import { NetworkTypes, UrlListInput, Utils } from 'easytier-frontend-lib';
import ApiClient, { type CentralNetworkSettings, type CentralNetworkSummary, type GatewayInfo } from '../modules/api';
import { normalizeVirtualSubnet } from '../modules/virtual-subnet';
@@ -33,12 +33,7 @@ const filteredNetworks = computed(() => {
const gatewayEnabled = computed(() => gatewayInfo.value?.enabled === true);
const protos: { [proto: string]: number } = {
tcp: 11010,
udp: 11010,
ws: 11011,
wss: 11012,
};
const protos = NetworkTypes.PEER_PROTOCOLS;
const networkingMethodLabels: { [method: string]: () => string } = {
PublicServer: () => t('public_server'),
@@ -243,6 +243,70 @@ test('network creation retains gateway and advanced standalone modes', async t =
assert.equal(state.writes.filter(w => w.path === '/networks').at(-1).payload.settings.networking_method, 'Standalone');
});
for (const action of ['creation', 'settings']) {
test(`network ${action} supports all initial-node protocols and preserves URLs`, async t => {
const { page, state } = await open(t, action === 'creation' ? '/h/networks' : '/h/networks/network-1', {}, state => {
state.gatewayEnabled = false;
state.networks[1].peer_urls = [];
state.networks[1].networking_method = 'Standalone';
});
if (action === 'creation') {
await page.getByRole('button', { name: 'Create Network', exact: true }).click();
await page.locator('#network-display-name').fill('Peer protocols');
} else {
await page.getByRole('tab', { name: 'Settings', exact: true }).click();
}
const peers = [
'tcp://peers.example:11010',
'udp://peers.example:11010',
'wg://peers.example:11011',
'ws://peers.example:11011/peers',
'wss://peers.example:11012/peers',
'quic://peers.example:11012',
'faketcp://peers.example:11013',
'http://peers.example:80/peers',
'https://peers.example:443/peers',
'txt://peers.example',
'srv://_easytier._tcp.peers.example',
];
const nodes = page.locator(action === 'creation' ? '#initial-nodes' : '#settings-initial-nodes');
for (const peer of peers) {
const url = new URL(peer);
const protocol = url.protocol.slice(0, -1);
await nodes.getByText('Add Initial Node', { exact: true }).click();
const row = nodes.locator('.url-input-full').last();
await row.locator('.p-autocomplete-dropdown').click();
const options = page.locator(`#${await row.getByRole('combobox').getAttribute('aria-controls')}`);
await options.getByRole('option', { name: protocol, exact: true }).click();
await row.locator('input.grow').first().fill(url.hostname);
if (url.pathname) await row.getByPlaceholder('/mypath').fill(url.pathname);
assert.equal(await row.getByRole('spinbutton').count(), ['txt', 'srv'].includes(protocol) ? 0 : 1);
}
if (action === 'creation') {
await page.getByRole('dialog').getByRole('button', { name: 'Confirm', exact: true }).click();
await page.waitForURL('**/networks/created-*');
} else {
const saved = page.waitForResponse(response => response.request().method() === 'PATCH');
await page.getByRole('button', { name: 'Save', exact: true }).click();
await saved;
}
let settings = state.writes.at(-1).payload.settings;
assert.equal(settings.networking_method, 'Manual');
assert.deepEqual(settings.peer_urls, peers);
await page.reload();
await page.getByRole('tab', { name: 'Settings', exact: true }).click();
const saved = page.waitForResponse(response => response.request().method() === 'PATCH');
await page.getByRole('button', { name: 'Save', exact: true }).click();
await saved;
settings = state.writes.at(-1).payload.settings;
assert.equal(settings.networking_method, 'Manual');
assert.deepEqual(settings.peer_urls, peers);
});
}
for (const [input, expected] of [
[' 10.200.0.0 ', '10.200.0.0/24'],
[' 10.200.0.0/16 ', '10.200.0.0/16'],