Compare commits

..

No commits in common. "84488b3e63441c33ae9eca1ee945d6dcb7af6115" and "ea1dd223b7c9f691415af9833cc1fd3d3aa7375f" have entirely different histories.

25 changed files with 3426 additions and 2841 deletions

View file

@ -1,35 +0,0 @@
// Folder-specific settings
//
// For a full list of overridable settings, and general information on folder-specific settings,
// see the documentation: https://zed.dev/docs/configuring-zed#folder-specific-settings
{
"prettier": {
"allowed": false
},
"languages": {
"JavaScript": {
"formatter": {
"code_actions": {
"source.fixAll.eslint": true
}
},
"tab_size": 2
},
"TypeScript": {
"formatter": {
"code_actions": {
"source.fixAll.eslint": true
}
},
"tab_size": 2
},
"Vue.js": {
"formatter": {
"code_actions": {
"source.fixAll.eslint": true
}
},
"tab_size": 2
}
}
}

View file

@ -13,13 +13,11 @@ export default [
}, },
}, },
plugins: { vueParser }, plugins: { vueParser },
files: ['src/**/*.js', 'src/**/*.ts', 'src/**/*.vue'],
rules: { rules: {
'semi': [ 'semi': [
'error', 'error',
'always', 'always',
], ],
'object-curly-spacing': ['warn', 'always'],
'comma-dangle': [ 'comma-dangle': [
'error', 'error',
'always-multiline', 'always-multiline',

5555
client/pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -34,7 +34,7 @@ const navRoutesNew = [
{ caption: 'Rules', icon: IRule, href: '/firewall/forward_rules' }, { caption: 'Rules', icon: IRule, href: '/firewall/forward_rules' },
{ caption: 'SNAT', icon: ISNAT, href: '/firewall/source_nat_rules' }, { caption: 'SNAT', icon: ISNAT, href: '/firewall/source_nat_rules' },
{ caption: 'DNAT', icon: IDNAT, href: '/firewall/destination_nat_rules' }, { caption: 'DNAT', icon: IDNAT, href: '/firewall/destination_nat_rules' },
] }, ]},
{ caption: 'Network', icon: INetwork, children: [ { caption: 'Network', icon: INetwork, children: [
{ caption: 'Interfaces', icon: IEthernet, href: '/network/interfaces' }, { caption: 'Interfaces', icon: IEthernet, href: '/network/interfaces' },
{ caption: 'Static Routes', icon: IStaticRoutes, href: '/network/static_routes' }, { caption: 'Static Routes', icon: IStaticRoutes, href: '/network/static_routes' },
@ -53,7 +53,7 @@ const navRoutesNew = [
{ caption: 'Status', icon: IDashboard, href: '/vpn/wireguard_status' }, { caption: 'Status', icon: IDashboard, href: '/vpn/wireguard_status' },
{ caption: 'Interfaces', icon: IEthernet, href: '/vpn/wireguard.interfaces' }, { caption: 'Interfaces', icon: IEthernet, href: '/vpn/wireguard.interfaces' },
{ caption: 'Peers', icon: INodes, href: '/vpn/wireguard.peers' }, { caption: 'Peers', icon: INodes, href: '/vpn/wireguard.peers' },
] }, ]},
] }, ] },
{ caption: 'Users', icon: IUser, href: '/system/users' }, { caption: 'Users', icon: IUser, href: '/system/users' },
{ caption: 'Config', icon: IConfig, href: '/config/config' }, { caption: 'Config', icon: IConfig, href: '/config/config' },

View file

@ -20,7 +20,7 @@ export async function apiCall(method: string, params: Record<string, any>): Prom
console.debug('[API] Calling ', method, params, pResult); console.debug('[API] Calling ', method, params, pResult);
const result = await pResult; const result = await pResult;
console.debug('[API] Response', method, result); console.debug('[API] Response', method, result);
return { Data: result, Error: null }; return { Data: result, Error: null};
} catch (ex: any){ } catch (ex: any){
if (ex.code === 401) { if (ex.code === 401) {
UnauthorizedCallback(); UnauthorizedCallback();
@ -28,33 +28,33 @@ export async function apiCall(method: string, params: Record<string, any>): Prom
$toast.error(`${method }: ${ ex.message}`); $toast.error(`${method }: ${ ex.message}`);
console.debug('[API] Error ', method, ex); console.debug('[API] Error ', method, ex);
} }
return { Data: null, Error: ex }; return { Data: null, Error: ex};
} }
} }
export async function authenticate(username: string, password: string): Promise<any> { export async function authenticate(username: string, password: string): Promise<any> {
const pResponse = axios.post('/login', { username, password }, { timeout: 10100 }); const pResponse = axios.post('/login', { username, password }, {timeout: 10100});
try { try {
const response = await pResponse; const response = await pResponse;
// Dont log this as the user password is inside: console.debug(response); // Dont log this as the user password is inside: console.debug(response);
return { data: response.data, error: null }; return { data: response.data, error: null};
} catch (error) { } catch (error) {
return { data: null, error: error }; return { data: null, error: error};
} }
} }
export async function logout(): Promise<any> { export async function logout(): Promise<any> {
const pResponse = axios.post('/logout', null, { timeout: 10100 }); const pResponse = axios.post('/logout', null, {timeout: 10100});
try { try {
const response = await pResponse; const response = await pResponse;
return { data: response.data, error: null }; return { data: response.data, error: null};
} catch (error) { } catch (error) {
return { data: null, error: error }; return { data: null, error: error};
} }
} }
export async function checkAuthentication() { export async function checkAuthentication() {
const pResponse = axios.post('/session', null, { timeout: 10100 }); const pResponse = axios.post('/session', null, {timeout: 10100});
try { try {
const response = await pResponse; const response = await pResponse;
const last_hash = window.localStorage.getItem('commit_hash'); const last_hash = window.localStorage.getItem('commit_hash');
@ -65,11 +65,11 @@ export async function checkAuthentication() {
window.location.reload(); window.location.reload();
} }
} else window.localStorage.setItem('commit_hash', response.data.commit_hash); } else window.localStorage.setItem('commit_hash', response.data.commit_hash);
return { auth: 2, error: null }; return {auth: 2, error: null};
} catch (error: any) { } catch (error: any) {
if (error.response.status == 401) { if (error.response.status == 401) {
return { auth: 0, error: null }; return {auth: 0, error: null};
} }
return { auth: 0, error: error }; return {auth: 0, error: error};
} }
} }

View file

@ -85,7 +85,7 @@ function toggleRowSelection(index: number) {
else if (shiftState) { // Selection becomes a range including the highest, lowest and clicked row else if (shiftState) { // Selection becomes a range including the highest, lowest and clicked row
const points = [Math.max(...selection), Math.min(...selection), index]; const points = [Math.max(...selection), Math.min(...selection), index];
const [max, min] = [Math.max(...points), Math.min(...points)]; const [max, min] = [Math.max(...points), Math.min(...points)];
selection = Array.from({ length: max - min + 1 }, (_, i) => i + min); selection = Array.from({length: max - min + 1}, (_, i) => i + min);
} else if (ctrlState) // Toggle the presence of the row in the selection } else if (ctrlState) // Toggle the presence of the row in the selection
selection = selection.includes(index) selection = selection.includes(index)
? selection.filter(i => i !== index) ? selection.filter(i => i !== index)

View file

@ -103,7 +103,7 @@ watch($$(search), async (val, oldVal) => {
async function performSearch(unknownKeys?: Index[]) { async function performSearch(unknownKeys?: Index[]) {
if (searchProvider !== null) if (searchProvider !== null)
options = await searchProvider({ search, unknownKeys }); options = await searchProvider({search, unknownKeys});
} }
async function expand() { async function expand() {

View file

@ -57,18 +57,18 @@ const GetPeers: SearchProvider = async (o) => {
}; };
const PortDefinition: Object = { const PortDefinition: Object = {
'any': { display: 'Any' }, 'any': { display: 'Any'},
'single': { 'single': {
display: 'Single', display: 'Single',
fields: { fields: {
port: { is: 'NumberBox', label: 'Port' }, port: { is: 'NumberBox', label: 'Port'},
}, },
}, },
'range': { 'range': {
display: 'Range', display: 'Range',
fields: { fields: {
start_port: { is: 'NumberBox', label: 'Start Port' }, start_port: { is: 'NumberBox', label: 'Start Port'},
end_port: { is: 'NumberBox', label: 'End Port' }, end_port: { is: 'NumberBox', label: 'End Port'},
}, },
}, },
}; };
@ -80,55 +80,55 @@ export const editTypes: { [key: string]: { [key: string]: any } } = {
name: 'Forward Rule', name: 'Forward Rule',
idType: 'Number', idType: 'Number',
fields: { fields: {
name: { is: 'TextBox', label: 'Name' }, name: { is: 'TextBox', label: 'Name'},
source_addresses: { is: 'MultiSelect', label: 'Source', props: { searchProvider: GetAddresses } }, source_addresses: { is: 'MultiSelect', label: 'Source', props: { searchProvider: GetAddresses}},
destination_addresses: { is: 'MultiSelect', label: 'Destination', props: { searchProvider: GetAddresses } }, destination_addresses: { is: 'MultiSelect', label: 'Destination', props: { searchProvider: GetAddresses}},
services: { is: 'MultiSelect', label: 'Services', props: { searchProvider: GetServices } }, services: { is: 'MultiSelect', label: 'Services', props: { searchProvider: GetServices}},
verdict: { is: 'EnumInput', label: 'Verdict', props: { variants: { verdict: { is: 'EnumInput', label: 'Verdict', props: { variants: {
'accept': { display: 'Accept' }, 'accept': { display: 'Accept'},
'drop': { display: 'Drop' }, 'drop': { display: 'Drop'},
'continue': { display: 'Continue' }, 'continue': { display: 'Continue'},
} } }, }}},
counter: { is: 'CheckBox', label: 'Counter' }, counter: { is: 'CheckBox', label: 'Counter'},
comment: { is: 'MultilineTextBox', label: 'Comment' }, comment: { is: 'MultilineTextBox', label: 'Comment'},
}, },
}, },
'destination_nat_rules': { 'destination_nat_rules': {
name: 'Destination NAT Rule', name: 'Destination NAT Rule',
idType: 'Number', idType: 'Number',
fields: { fields: {
name: { is: 'TextBox', label: 'Name' }, name: { is: 'TextBox', label: 'Name'},
source_addresses: { is: 'MultiSelect', label: 'Source', props: { searchProvider: GetAddresses } }, source_addresses: { is: 'MultiSelect', label: 'Source', props: { searchProvider: GetAddresses}},
destination_addresses: { is: 'MultiSelect', label: 'Destination', props: { searchProvider: GetAddresses } }, destination_addresses: { is: 'MultiSelect', label: 'Destination', props: { searchProvider: GetAddresses}},
services: { is: 'MultiSelect', label: 'Services', props: { searchProvider: GetServices } }, services: { is: 'MultiSelect', label: 'Services', props: { searchProvider: GetServices}},
dnat_heading: { is: 'Heading', props: { caption: 'DNAT' } }, dnat_heading: { is: 'Heading', props: { caption: 'DNAT' }},
dnat_address: { is: 'SingleSelect', label: 'Destination', props: { searchProvider: GetAddresses } }, dnat_address: { is: 'SingleSelect', label: 'Destination', props: { searchProvider: GetAddresses}},
dnat_service: { is: 'SingleSelect', label: 'Service', props: { searchProvider: GetServices } }, dnat_service: { is: 'SingleSelect', label: 'Service', props: { searchProvider: GetServices}},
counter: { is: 'CheckBox', label: 'Counter' }, counter: { is: 'CheckBox', label: 'Counter'},
comment: { is: 'MultilineTextBox', label: 'Comment' }, comment: { is: 'MultilineTextBox', label: 'Comment'},
}, },
}, },
'source_nat_rules': { 'source_nat_rules': {
name: 'Source NAT Rule', name: 'Source NAT Rule',
idType: 'Number', idType: 'Number',
fields: { fields: {
name: { is: 'TextBox', label: 'Name' }, name: { is: 'TextBox', label: 'Name'},
source_addresses: { is: 'MultiSelect', label: 'Source', props: { searchProvider: GetAddresses } }, source_addresses: { is: 'MultiSelect', label: 'Source', props: { searchProvider: GetAddresses}},
destination_addresses: { is: 'MultiSelect', label: 'Destination', props: { searchProvider: GetAddresses } }, destination_addresses: { is: 'MultiSelect', label: 'Destination', props: { searchProvider: GetAddresses}},
services: { is: 'MultiSelect', label: 'Services', props: { searchProvider: GetServices } }, services: { is: 'MultiSelect', label: 'Services', props: { searchProvider: GetServices}},
snat_heading: { is: 'Heading', props: { caption: 'SNAT' } }, snat_heading: { is: 'Heading', props: { caption: 'SNAT' }},
snat_type: { is: 'EnumInput', label: 'Type', props: { variants: { snat_type: { is: 'EnumInput', label: 'Type', props: { variants: {
'masquerade': { display: 'Masquerade' }, 'masquerade': { display: 'Masquerade' },
'snat': { 'snat': {
display: 'SNAT', display: 'SNAT',
fields: { fields: {
address: { is: 'SingleSelect', label: 'Source', props: { searchProvider: GetAddresses } }, address: { is: 'SingleSelect', label: 'Source', props: { searchProvider: GetAddresses}},
service: { is: 'SingleSelect', label: 'Service', props: { searchProvider: GetServices } }, service: { is: 'SingleSelect', label: 'Service', props: { searchProvider: GetServices}},
}, },
}, },
} } }, }}},
counter: { is: 'CheckBox', label: 'Counter' }, counter: { is: 'CheckBox', label: 'Counter'},
comment: { is: 'MultilineTextBox', label: 'Comment' }, comment: { is: 'MultilineTextBox', label: 'Comment'},
}, },
}, },
}, },
@ -137,58 +137,58 @@ export const editTypes: { [key: string]: { [key: string]: any } } = {
'interfaces': { 'interfaces': {
name: 'Interface', name: 'Interface',
fields: { fields: {
name: { is: 'TextBox', label: 'Name' }, name: { is: 'TextBox', label: 'Name'},
alias: { is: 'TextBox', label: 'Alias' }, alias: { is: 'TextBox', label: 'Alias'},
interface_type: { is: 'EnumInput', label: 'Type', props: { variants: { interface_type: { is: 'EnumInput', label: 'Type', props: { variants: {
'hardware': { 'hardware': {
display: 'Hardware', display: 'Hardware',
fields: { fields: {
device: { is: 'SingleSelect', label: 'Device', props: { searchProvider: GetHardwareInterfaces } }, device: { is: 'SingleSelect', label: 'Device', props: { searchProvider: GetHardwareInterfaces }},
}, },
}, },
'vlan': { 'vlan': {
display: 'VLAN', display: 'VLAN',
fields: { fields: {
parent: { is: 'SingleSelect', label: 'VLAN Parent', props: { searchProvider: GetInterfaces } }, parent: { is: 'SingleSelect', label: 'VLAN Parent', props: { searchProvider: GetInterfaces}},
id: { is: 'NumberBox', label: 'VLAN ID', props: { min: 1, max: 4094 } }, id: { is: 'NumberBox', label: 'VLAN ID', props: { min: 1, max: 4094 }},
}, },
}, },
'bond': { 'bond': {
display: 'Bond', display: 'Bond',
fields: { fields: {
members: { is: 'MultiSelect', label: 'Members', props: { searchProvider: GetInterfaces } }, members: { is: 'MultiSelect', label: 'Members', props: { searchProvider: GetInterfaces}},
}, },
}, },
'bridge': { 'bridge': {
display: 'Bridge', display: 'Bridge',
fields: { fields: {
members: { is: 'MultiSelect', label: 'Members', props: { searchProvider: GetInterfaces } }, members: { is: 'MultiSelect', label: 'Members', props: { searchProvider: GetInterfaces}},
}, },
}, },
} } }, }}},
addressing_mode: { is: 'EnumInput', label: 'Addressing Mode', props: { variants: { addressing_mode: { is: 'EnumInput', label: 'Addressing Mode', props: { variants: {
'none': { display: 'None' }, 'none': { display: 'None' },
'static': { 'static': {
display: 'Static', display: 'Static',
fields: { fields: {
address: { is: 'TextBox', label: 'Address' }, address: { is: 'TextBox', label: 'Address'},
}, },
}, },
'dhcp': { display: 'DHCP' }, 'dhcp': { display: 'DHCP' },
} } }, }}},
comment: { is: 'MultilineTextBox', label: 'Comment' }, comment: { is: 'MultilineTextBox', label: 'Comment'},
}, },
}, },
'static_routes': { 'static_routes': {
name: 'Static Route', name: 'Static Route',
idType: 'Number', idType: 'Number',
fields: { fields: {
name: { is: 'TextBox', label: 'Name' }, name: { is: 'TextBox', label: 'Name'},
interface: { is: 'SingleSelect', label: 'Interface', props: { searchProvider: GetInterfaces } }, interface: { is: 'SingleSelect', label: 'Interface', props: { searchProvider: GetInterfaces} },
gateway: { is: 'TextBox', label: 'Gateway' }, gateway: { is: 'TextBox', label: 'Gateway'},
destination: { is: 'TextBox', label: 'Destination' }, destination: { is: 'TextBox', label: 'Destination'},
metric: { is: 'NumberBox', label: 'Metric' }, metric: { is: 'NumberBox', label: 'Metric'},
comment: { is: 'MultilineTextBox', label: 'Comment' }, comment: { is: 'MultilineTextBox', label: 'Comment'},
}, },
}, },
}, },
@ -197,69 +197,69 @@ export const editTypes: { [key: string]: { [key: string]: any } } = {
'addresses': { 'addresses': {
name: 'Address', name: 'Address',
fields: { fields: {
name: { is: 'TextBox', label: 'Name' }, name: { is: 'TextBox', label: 'Name'},
address_type: { is: 'EnumInput', label: 'Type', props: { variants: { address_type: { is: 'EnumInput', label: 'Type', props: { variants: {
'host': { 'host': {
display: 'Host', display: 'Host',
fields: { fields: {
address: { is: 'TextBox', label: 'Address' }, address: { is: 'TextBox', label: 'Address'},
}, },
}, },
'range': { 'range': {
display: 'Range', display: 'Range',
fields: { fields: {
range: { is: 'TextBox', label: 'Range' }, range: { is: 'TextBox', label: 'Range'},
}, },
}, },
'network': { 'network': {
display: 'Network', display: 'Network',
fields: { fields: {
network: { is: 'TextBox', label: 'Network' }, network: { is: 'TextBox', label: 'Network'},
}, },
}, },
'group': { 'group': {
display: 'Group', display: 'Group',
fields: { fields: {
members: { is: 'MultiSelect', label: 'Members', props: { searchProvider: GetAddresses } }, members: { is: 'MultiSelect', label: 'Members', props: { searchProvider: GetAddresses}},
}, },
}, },
} } }, }}},
comment: { is: 'MultilineTextBox', label: 'Comment' }, comment: { is: 'MultilineTextBox', label: 'Comment'},
}, },
}, },
'services': { 'services': {
name: 'Service', name: 'Service',
fields: { fields: {
name: { is: 'TextBox', label: 'Name' }, name: { is: 'TextBox', label: 'Name'},
service_type: { is: 'EnumInput', label: 'Type', props: { variants: { service_type: { is: 'EnumInput', label: 'Type', props: { variants: {
'tcp': { 'tcp': {
display: 'TCP', display: 'TCP',
fields: { fields: {
source: { is: 'EnumInput', label: 'Source', props: { variants: PortDefinition } }, source: { is: 'EnumInput', label: 'Source', props: { variants: PortDefinition }},
destination: { is: 'EnumInput', label: 'Destination', props: { variants: PortDefinition } }, destination: { is: 'EnumInput', label: 'Destination', props: { variants: PortDefinition }},
}, },
}, },
'udp': { 'udp': {
display: 'UDP', display: 'UDP',
fields: { fields: {
source: { is: 'EnumInput', label: 'Source', props: { variants: PortDefinition } }, source: { is: 'EnumInput', label: 'Source', props: { variants: PortDefinition }},
destination: { is: 'EnumInput', label: 'Destination', props: { variants: PortDefinition } }, destination: { is: 'EnumInput', label: 'Destination', props: { variants: PortDefinition }},
}, },
}, },
'icmp': { 'icmp': {
display: 'ICMP', display: 'ICMP',
fields: { fields: {
icmp_code: { is: 'NumberBox', label: 'ICMP Code' }, icmp_code: { is: 'NumberBox', label: 'ICMP Code'},
}, },
}, },
'group': { 'group': {
display: 'Group', display: 'Group',
fields: { fields: {
members: { is: 'MultiSelect', label: 'Members', props: { searchProvider: GetServices } }, members: { is: 'MultiSelect', label: 'Members', props: { searchProvider: GetServices}},
}, },
}, },
} } }, }}},
comment: { is: 'MultilineTextBox', label: 'Comment' }, comment: { is: 'MultilineTextBox', label: 'Comment'},
}, },
}, },
}, },
@ -269,59 +269,59 @@ export const editTypes: { [key: string]: { [key: string]: any } } = {
name: 'DHCP Server', name: 'DHCP Server',
idType: 'Number', idType: 'Number',
fields: { fields: {
name: { is: 'TextBox', label: 'Name' }, name: { is: 'TextBox', label: 'Name'},
interface: { is: 'SingleSelect', label: 'Interface', props: { searchProvider: GetInterfaces } }, interface: { is: 'SingleSelect', label: 'Interface', props: { searchProvider: GetInterfaces} },
pool: { is: 'MultiSelect', label: 'Pool', props: { searchProvider: GetAddresses } }, pool: { is: 'MultiSelect', label: 'Pool', props: { searchProvider: GetAddresses} },
gateway_mode: { is: 'EnumInput', label: 'Gateway Mode', props: { variants: { gateway_mode: { is: 'EnumInput', label: 'Gateway Mode', props: { variants: {
'none': { display: 'None' }, 'none': { display: 'None' },
'interface': { display: 'Interface' }, 'interface': { display: 'Interface' },
'specify': { 'specify': {
display: 'Specify', display: 'Specify',
fields: { fields: {
gateway: { is: 'SingleSelect', label: 'Gateway', props: { searchProvider: GetAddresses } }, gateway: { is: 'SingleSelect', label: 'Gateway', props: { searchProvider: GetAddresses} },
}, },
}, },
} } }, }}},
dns_server_mode: { is: 'EnumInput', label: 'DNS Server Mode', props: { variants: { dns_server_mode: { is: 'EnumInput', label: 'DNS Server Mode', props: { variants: {
'none': { display: 'None' }, 'none': { display: 'None' },
'interface': { display: 'Interface' }, 'interface': { display: 'Interface' },
'specify': { 'specify': {
display: 'Specify', display: 'Specify',
fields: { fields: {
dns_servers: { is: 'MultiSelect', label: 'DNS Servers', props: { searchProvider: GetAddresses } }, dns_servers: { is: 'MultiSelect', label: 'DNS Servers', props: { searchProvider: GetAddresses} },
}, },
}, },
} } }, }}},
ntp_server_mode: { is: 'EnumInput', label: 'NTP Server Mode', props: { variants: { ntp_server_mode: { is: 'EnumInput', label: 'NTP Server Mode', props: { variants: {
'none': { display: 'None' }, 'none': { display: 'None' },
'interface': { display: 'Interface' }, 'interface': { display: 'Interface' },
'specify': { 'specify': {
display: 'Specify', display: 'Specify',
fields: { fields: {
ntp_servers: { is: 'MultiSelect', label: 'NTP Servers', props: { searchProvider: GetAddresses } }, ntp_servers: { is: 'MultiSelect', label: 'NTP Servers', props: { searchProvider: GetAddresses} },
}, },
}, },
} } }, }}},
lease_time: { is: 'NumberBox', label: 'Lease Time' }, lease_time: { is: 'NumberBox', label: 'Lease Time'},
comment: { is: 'MultilineTextBox', label: 'Comment' }, comment: { is: 'MultilineTextBox', label: 'Comment'},
}, },
}, },
'ntp_servers': { 'ntp_servers': {
name: 'NTP Server', name: 'NTP Server',
idType: 'Number', idType: 'Number',
fields: { fields: {
name: { is: 'TextBox', label: 'Name' }, name: { is: 'TextBox', label: 'Name'},
interface: { is: 'SingleSelect', label: 'Interface', props: { searchProvider: GetInterfaces } }, interface: { is: 'SingleSelect', label: 'Interface', props: { searchProvider: GetInterfaces} },
comment: { is: 'MultilineTextBox', label: 'Comment' }, comment: { is: 'MultilineTextBox', label: 'Comment'},
}, },
}, },
'dns_servers': { 'dns_servers': {
name: 'DNS Server', name: 'DNS Server',
idType: 'Number', idType: 'Number',
fields: { fields: {
name: { is: 'TextBox', label: 'Name' }, name: { is: 'TextBox', label: 'Name'},
interface: { is: 'SingleSelect', label: 'Interface', props: { searchProvider: GetInterfaces } }, interface: { is: 'SingleSelect', label: 'Interface', props: { searchProvider: GetInterfaces} },
comment: { is: 'MultilineTextBox', label: 'Comment' }, comment: { is: 'MultilineTextBox', label: 'Comment'},
}, },
}, },
}, },
@ -330,24 +330,24 @@ export const editTypes: { [key: string]: { [key: string]: any } } = {
'wireguard.interfaces': { 'wireguard.interfaces': {
name: 'Wireguard Interface', name: 'Wireguard Interface',
fields: { fields: {
name: { is: 'TextBox', label: 'Name' }, name: { is: 'TextBox', label: 'Name'},
public_key: { is: 'TextBox', label: 'Public Key' }, public_key: { is: 'TextBox', label: 'Public Key'},
private_key: { is: 'TextBox', label: 'Private Key' }, private_key: { is: 'TextBox', label: 'Private Key'},
listen_port: { is: 'NumberBox', label: 'Listen Port' }, listen_port: { is: 'NumberBox', label: 'Listen Port'},
peers: { is: 'MultiSelect', label: 'Peers', props: { searchProvider: GetPeers } }, peers: { is: 'MultiSelect', label: 'Peers', props: { searchProvider: GetPeers} },
comment: { is: 'MultilineTextBox', label: 'Comment' }, comment: { is: 'MultilineTextBox', label: 'Comment'},
}, },
}, },
'wireguard.peers': { 'wireguard.peers': {
name: 'Wireguard Peer', name: 'Wireguard Peer',
fields: { fields: {
name: { is: 'TextBox', label: 'Name' }, name: { is: 'TextBox', label: 'Name'},
public_key: { is: 'TextBox', label: 'Public Key' }, public_key: { is: 'TextBox', label: 'Public Key'},
preshared_key: { is: 'TextBox', label: 'Preshared Key' }, preshared_key: { is: 'TextBox', label: 'Preshared Key'},
allowed_ips: { is: 'MultiSelect', label: 'Allowed IPs', props: { searchProvider: GetAddresses } }, allowed_ips: { is: 'MultiSelect', label: 'Allowed IPs', props: { searchProvider: GetAddresses} },
endpoint: { is: 'TextBox', label: 'Endpoint' }, endpoint: { is: 'TextBox', label: 'Endpoint'},
persistent_keepalive: { is: 'NumberBox', label: 'Persistent Keepalive' }, persistent_keepalive: { is: 'NumberBox', label: 'Persistent Keepalive'},
comment: { is: 'MultilineTextBox', label: 'Comment' }, comment: { is: 'MultilineTextBox', label: 'Comment'},
}, },
}, },
}, },
@ -356,9 +356,9 @@ export const editTypes: { [key: string]: { [key: string]: any } } = {
'users': { 'users': {
name: 'User', name: 'User',
fields: { fields: {
name: { is: 'TextBox', label: 'Name' }, name: { is: 'TextBox', label: 'Name'},
password: { is: 'TextBox', label: 'Password' }, password: { is: 'TextBox', label: 'Password'},
comment: { is: 'MultilineTextBox', label: 'Comment' }, comment: { is: 'MultilineTextBox', label: 'Comment'},
}, },
}, },
}, },

View file

@ -14,9 +14,9 @@ async function load(){
loading = true; loading = true;
let res: any; let res: any;
if (editTypes[subsystem][entity].idType == 'Number') { if (editTypes[subsystem][entity].idType == 'Number') {
res = await apiCall(`${subsystem}.${entity}.get`, { index: id as number - 0 }); res = await apiCall(`${subsystem}.${entity}.get`, {index: id as number - 0});
} else { } else {
res = await apiCall(`${subsystem}.${entity}.get`, { name: id }); res = await apiCall(`${subsystem}.${entity}.get`, {name: id});
} }
if (res.Error === null) { if (res.Error === null) {
@ -33,15 +33,15 @@ async function update() {
let res: any; let res: any;
if (editTypes[subsystem][entity].idType == 'Number') { if (editTypes[subsystem][entity].idType == 'Number') {
res = await apiCall(`${subsystem}.${entity}.update`, { index: id as number - 0, thing: vm }); res = await apiCall(`${subsystem}.${entity}.update`, {index: id as number - 0, thing: vm});
} else { } else {
if (id != vm.name) { if (id != vm.name) {
if (confirm('You are about to Change the name and all references, are you Sure?')) { if (confirm('You are about to Change the name and all references, are you Sure?')) {
res = await apiCall(`${subsystem}.${entity}.update`, { name: id, thing: vm }); res = await apiCall(`${subsystem}.${entity}.update`, {name: id, thing: vm});
} }
} else { } else {
res = await apiCall(`${subsystem}.${entity}.update`, { name: id, thing: vm }); res = await apiCall(`${subsystem}.${entity}.update`, {name: id, thing: vm});
} }
} }

View file

@ -8,9 +8,9 @@ let changelog = $ref([]);
let loading = $ref(false); let loading = $ref(false);
const columns = [ const columns = [
{ heading: 'Path', path: 'path' }, {heading: 'Path', path: 'path'},
{ heading: 'Action', path: 'action' }, {heading: 'Action', path: 'action'},
{ heading: 'ID', path: 'id' }, {heading: 'ID', path: 'id'},
]; ];
const displayData = $computed(() => { const displayData = $computed(() => {

View file

@ -8,14 +8,14 @@ let loading = $ref(false);
let selection = $ref([] as number[]); let selection = $ref([] as number[]);
const columns = [ const columns = [
{ heading: 'Name', path: 'name' }, {heading: 'Name', path: 'name'},
{ heading: 'Source', path: 'source_addresses' }, {heading: 'Source', path: 'source_addresses'},
{ heading: 'Destination', path: 'destination_addresses' }, {heading: 'Destination', path: 'destination_addresses'},
{ heading: 'Service', path: 'services' }, {heading: 'Service', path: 'services'},
{ heading: 'Translated Address', path: 'dnat_address' }, {heading: 'Translated Address', path: 'dnat_address'},
{ heading: 'Translated Service', path: 'dnat_service' }, {heading: 'Translated Service', path: 'dnat_service'},
{ heading: 'Counter', path: 'counter' }, {heading: 'Counter', path: 'counter'},
{ heading: 'Comment', path: 'comment' }, {heading: 'Comment', path: 'comment'},
]; ];
async function load(){ async function load(){
@ -29,7 +29,7 @@ async function load(){
} }
async function deleteRule(){ async function deleteRule(){
let res = await apiCall('firewall.destination_nat_rules.delete', { id: selection[0] }); let res = await apiCall('firewall.destination_nat_rules.delete', {id: selection[0]});
if (res.Error === null) { if (res.Error === null) {
console.debug('deleted rule'); console.debug('deleted rule');
p.toast.success('Deleted Rule'); p.toast.success('Deleted Rule');
@ -41,7 +41,7 @@ async function deleteRule(){
async function draggedRow(draggedRow: number, draggedOverRow: number) { async function draggedRow(draggedRow: number, draggedOverRow: number) {
console.log('dragged', draggedRow, draggedOverRow); console.log('dragged', draggedRow, draggedOverRow);
let res = await apiCall('firewall.destination_nat_rules.move', { index: draggedRow, to_index: draggedOverRow }); let res = await apiCall('firewall.destination_nat_rules.move', {index: draggedRow, to_index: draggedOverRow});
if (res.Error === null) { if (res.Error === null) {
console.debug('moved rule'); console.debug('moved rule');
p.toast.success('Moved Rule'); p.toast.success('Moved Rule');

View file

@ -9,13 +9,13 @@ let loading = $ref(false);
let selection = $ref([] as number[]); let selection = $ref([] as number[]);
const columns = [ const columns = [
{ heading: 'Name', path: 'name' }, {heading: 'Name', path: 'name'},
{ heading: 'Source', path: 'source_addresses', component: markRaw(ArrayDisplay), componentProp: 'data' }, {heading: 'Source', path: 'source_addresses', component: markRaw(ArrayDisplay), componentProp: 'data'},
{ heading: 'Destination', path: 'destination_addresses', component: markRaw(ArrayDisplay), componentProp: 'data' }, {heading: 'Destination', path: 'destination_addresses', component: markRaw(ArrayDisplay), componentProp: 'data'},
{ heading: 'Service', path: 'services', component: markRaw(ArrayDisplay), componentProp: 'data' }, {heading: 'Service', path: 'services', component: markRaw(ArrayDisplay), componentProp: 'data'},
{ heading: 'Verdict', path: 'verdict' }, {heading: 'Verdict', path: 'verdict'},
{ heading: 'Counter', path: 'counter' }, {heading: 'Counter', path: 'counter'},
{ heading: 'Comment', path: 'comment' }, {heading: 'Comment', path: 'comment'},
]; ];
async function load(){ async function load(){
@ -29,7 +29,7 @@ async function load(){
} }
async function deleteRule(){ async function deleteRule(){
let res = await apiCall('firewall.forward_rules.delete', { id: selection[0] }); let res = await apiCall('firewall.forward_rules.delete', {id: selection[0]});
if (res.Error === null) { if (res.Error === null) {
console.debug('deleted rule'); console.debug('deleted rule');
p.toast.success('Deleted Rule'); p.toast.success('Deleted Rule');
@ -41,7 +41,7 @@ async function deleteRule(){
async function draggedRow(draggedRow: number, draggedOverRow: number) { async function draggedRow(draggedRow: number, draggedOverRow: number) {
console.log('dragged', draggedRow, draggedOverRow); console.log('dragged', draggedRow, draggedOverRow);
let res = await apiCall('firewall.forward_rules.move', { index: draggedRow, to_index: draggedOverRow }); let res = await apiCall('firewall.forward_rules.move', {index: draggedRow, to_index: draggedOverRow});
if (res.Error === null) { if (res.Error === null) {
console.debug('moved rule'); console.debug('moved rule');
p.toast.success('Moved Rule'); p.toast.success('Moved Rule');

View file

@ -8,14 +8,14 @@ let loading = $ref(false);
let selection = $ref([] as number[]); let selection = $ref([] as number[]);
const columns = [ const columns = [
{ heading: 'Name', path: 'name' }, {heading: 'Name', path: 'name'},
{ heading: 'Source', path: 'source_addresses' }, {heading: 'Source', path: 'source_addresses'},
{ heading: 'Destination', path: 'destination_addresses' }, {heading: 'Destination', path: 'destination_addresses'},
{ heading: 'Service', path: 'services' }, {heading: 'Service', path: 'services'},
{ heading: 'Translated Address', path: 'snat_type.snat.address' }, {heading: 'Translated Address', path: 'snat_type.snat.address'},
{ heading: 'Translated Service', path: 'snat_type.snat.service' }, {heading: 'Translated Service', path: 'snat_type.snat.service'},
{ heading: 'Counter', path: 'counter' }, {heading: 'Counter', path: 'counter'},
{ heading: 'Comment', path: 'comment' }, {heading: 'Comment', path: 'comment'},
]; ];
async function load(){ async function load(){
@ -29,7 +29,7 @@ async function load(){
} }
async function deleteRule(){ async function deleteRule(){
let res = await apiCall('firewall.source_nat_rules.delete', { id: selection[0] }); let res = await apiCall('firewall.source_nat_rules.delete', {id: selection[0]});
if (res.Error === null) { if (res.Error === null) {
console.debug('deleted rule'); console.debug('deleted rule');
p.toast.success('Deleted Rule'); p.toast.success('Deleted Rule');
@ -41,7 +41,7 @@ async function deleteRule(){
async function draggedRow(draggedRow: number, draggedOverRow: number) { async function draggedRow(draggedRow: number, draggedOverRow: number) {
console.log('dragged', draggedRow, draggedOverRow); console.log('dragged', draggedRow, draggedOverRow);
let res = await apiCall('firewall.source_nat_rules.move', { index: draggedRow, to_index: draggedOverRow }); let res = await apiCall('firewall.source_nat_rules.move', {index: draggedRow, to_index: draggedOverRow});
if (res.Error === null) { if (res.Error === null) {
console.debug('moved rule'); console.debug('moved rule');
p.toast.success('Moved Rule'); p.toast.success('Moved Rule');

View file

@ -8,11 +8,11 @@ let loading = $ref(false);
let selection = $ref([] as number[]); let selection = $ref([] as number[]);
const columns = [ const columns = [
{ heading: 'Name', path: 'name' }, {heading: 'Name', path: 'name'},
{ heading: 'Type', path: 'type' }, {heading: 'Type', path: 'type'},
{ heading: 'Members', path: 'members' }, {heading: 'Members', path: 'members'},
{ heading: 'Addressing Mode', path: 'addressing_mode' }, {heading: 'Addressing Mode', path: 'addressing_mode'},
{ heading: 'Address', path: 'address' }, {heading: 'Address', path: 'address'},
]; ];
const displayData = $computed(() => { const displayData = $computed(() => {
@ -43,7 +43,7 @@ async function load(){
} }
async function deleteInterface(){ async function deleteInterface(){
let res = await apiCall('network.interfaces.delete', { name: displayData[selection[0]].name }); let res = await apiCall('network.interfaces.delete', {name: displayData[selection[0]].name});
if (res.Error === null) { if (res.Error === null) {
console.debug('deleted interface'); console.debug('deleted interface');
} else { } else {

View file

@ -6,11 +6,11 @@ let loading = $ref(false);
let selection = $ref([] as number[]); let selection = $ref([] as number[]);
const columns = [ const columns = [
{ heading: 'Name', path: 'name' }, {heading: 'Name', path: 'name'},
{ heading: 'Interface', path: 'interface' }, {heading: 'Interface', path: 'interface'},
{ heading: 'Gateway', path: 'gateway' }, {heading: 'Gateway', path: 'gateway'},
{ heading: 'Destination', path: 'destination' }, {heading: 'Destination', path: 'destination'},
{ heading: 'Metric', path: 'metric' }, {heading: 'Metric', path: 'metric'},
]; ];
async function load(){ async function load(){
@ -26,7 +26,7 @@ async function load(){
} }
async function deleteStaticRoutes(){ async function deleteStaticRoutes(){
let res = await apiCall('network.static_routes.delete', { id: selection[0] }); let res = await apiCall('network.static_routes.delete', {id: selection[0]});
if (res.Error === null) { if (res.Error === null) {
console.debug('deleted static routes'); console.debug('deleted static routes');
} else { } else {

View file

@ -8,10 +8,10 @@ let loading = $ref(false);
let selection = $ref([] as number[]); let selection = $ref([] as number[]);
const columns = [ const columns = [
{ heading: 'Name', path: 'name' }, {heading: 'Name', path: 'name'},
{ heading: 'Type', path: 'type' }, {heading: 'Type', path: 'type'},
{ heading: 'Value', path: 'value' }, {heading: 'Value', path: 'value'},
{ heading: 'Comment', path: 'comment' }, {heading: 'Comment', path: 'comment'},
]; ];
async function load(){ async function load(){
@ -62,7 +62,7 @@ function getAddressValue(s: any): string {
} }
async function deleteAddress(){ async function deleteAddress(){
let res = await apiCall('object.addresses_delete', { id: displayData[selection[0]].name }); let res = await apiCall('object.addresses_delete', {id: displayData[selection[0]].name});
if (res.Error === null) { if (res.Error === null) {
console.debug('deleted address'); console.debug('deleted address');
} else { } else {

View file

@ -8,10 +8,10 @@ let loading = $ref(false);
let selection = $ref([] as number[]); let selection = $ref([] as number[]);
const columns = [ const columns = [
{ heading: 'Name', path: 'name' }, {heading: 'Name', path: 'name'},
{ heading: 'Type', path: 'type' }, {heading: 'Type', path: 'type'},
{ heading: 'Value', path: 'value' }, {heading: 'Value', path: 'value'},
{ heading: 'Comment', path: 'comment' }, {heading: 'Comment', path: 'comment'},
]; ];
const displayData = $computed(() => { const displayData = $computed(() => {
@ -65,7 +65,7 @@ async function load(){
} }
async function deleteService(){ async function deleteService(){
let res = await apiCall('object.services.delete', { name: displayData[selection[0]].name }); let res = await apiCall('object.services.delete', {name: displayData[selection[0]].name});
if (res.Error === null) { if (res.Error === null) {
console.debug('deleted service'); console.debug('deleted service');
} else { } else {

View file

@ -8,8 +8,8 @@ let loading = $ref(false);
let selection = $ref([] as number[]); let selection = $ref([] as number[]);
const columns = [ const columns = [
{ heading: 'Interface', path: 'interface' }, {heading: 'Interface', path: 'interface'},
{ heading: 'Comment', path: 'comment' }, {heading: 'Comment', path: 'comment'},
]; ];
async function load(){ async function load(){
@ -23,7 +23,7 @@ async function load(){
} }
async function deleteRule(){ async function deleteRule(){
let res = await apiCall('service.dhcp_servers.delete', { index: selection[0] }); let res = await apiCall('service.dhcp_servers.delete', {index: selection[0]});
if (res.Error === null) { if (res.Error === null) {
console.debug('deleted server'); console.debug('deleted server');
p.toast.success('Deleted DHCP Server'); p.toast.success('Deleted DHCP Server');

View file

@ -8,8 +8,8 @@ let loading = $ref(false);
let selection = $ref([] as number[]); let selection = $ref([] as number[]);
const columns = [ const columns = [
{ heading: 'Interface', path: 'interface' }, {heading: 'Interface', path: 'interface'},
{ heading: 'Comment', path: 'comment' }, {heading: 'Comment', path: 'comment'},
]; ];
async function load(){ async function load(){
@ -23,7 +23,7 @@ async function load(){
} }
async function deleteRule(){ async function deleteRule(){
let res = await apiCall('service.dns_servers.delete', { index: selection[0] }); let res = await apiCall('service.dns_servers.delete', {index: selection[0]});
if (res.Error === null) { if (res.Error === null) {
console.debug('deleted server'); console.debug('deleted server');
p.toast.success('Deleted DNS Server'); p.toast.success('Deleted DNS Server');

View file

@ -8,8 +8,8 @@ let loading = $ref(false);
let selection = $ref([] as number[]); let selection = $ref([] as number[]);
const columns = [ const columns = [
{ heading: 'Interface', path: 'interface' }, {heading: 'Interface', path: 'interface'},
{ heading: 'Comment', path: 'comment' }, {heading: 'Comment', path: 'comment'},
]; ];
async function load(){ async function load(){
@ -23,7 +23,7 @@ async function load(){
} }
async function deleteRule(){ async function deleteRule(){
let res = await apiCall('service.ntp_server.delete', { id: selection[0] }); let res = await apiCall('service.ntp_server.delete', {id: selection[0]});
if (res.Error === null) { if (res.Error === null) {
console.debug('deleted server'); console.debug('deleted server');
p.toast.success('Deleted NTP Server'); p.toast.success('Deleted NTP Server');

View file

@ -8,8 +8,8 @@ let loading = $ref(false);
let selection = $ref([] as number[]); let selection = $ref([] as number[]);
const columns = [ const columns = [
{ heading: 'Name', path: 'name' }, {heading: 'Name', path: 'name'},
{ heading: 'Comment', path: 'comment' }, {heading: 'Comment', path: 'comment'},
]; ];
async function load(){ async function load(){
@ -25,7 +25,7 @@ async function load(){
} }
async function deleteUser(){ async function deleteUser(){
let res = await apiCall('system.users.delete', { name: users[selection[0]].name }); let res = await apiCall('system.users.delete', {name: users[selection[0]].name});
if (res.Error === null) { if (res.Error === null) {
console.debug('deleted user'); console.debug('deleted user');
} else { } else {

View file

@ -8,7 +8,7 @@ const testValues: Options = {
a: { display: 'Option a' }, a: { display: 'Option a' },
z: { display: 'Option z' }, z: { display: 'Option z' },
}; };
let vm: any = $ref({ Multiple: [1] }); let vm: any = $ref({Multiple: [1]});
function genSP(indexIsChar: boolean): SearchProvider { function genSP(indexIsChar: boolean): SearchProvider {
return async (o) => { return async (o) => {

View file

@ -8,10 +8,10 @@ let loading = $ref(false);
let selection = $ref([] as number[]); let selection = $ref([] as number[]);
const columns = [ const columns = [
{ heading: 'Name', path: 'name' }, {heading: 'Name', path: 'name'},
{ heading: 'Listen Port', path: 'listen_port' }, {heading: 'Listen Port', path: 'listen_port'},
{ heading: 'Peers', path: 'peers' }, {heading: 'Peers', path: 'peers'},
{ heading: 'Comment', path: 'comment' }, {heading: 'Comment', path: 'comment'},
]; ];
@ -42,7 +42,7 @@ async function load(){
} }
async function deleteInterface(){ async function deleteInterface(){
let res = await apiCall('vpn.wireguard.interfaces.delete', { name: displayData[selection[0]].name }); let res = await apiCall('vpn.wireguard.interfaces.delete', {name: displayData[selection[0]].name});
if (res.Error === null) { if (res.Error === null) {
console.debug('deleted interface'); console.debug('deleted interface');
} else { } else {

View file

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { apiCall } from '../../api'; import { apiCall } from "../../api";
import getPlugins from '../../plugins'; import getPlugins from "../../plugins";
const p = getPlugins(); const p = getPlugins();
let peers = $ref({}); let peers = $ref({});
@ -8,11 +8,11 @@ let loading = $ref(false);
let selection = $ref([] as number[]); let selection = $ref([] as number[]);
const columns = [ const columns = [
{ heading: 'Name', path: 'name' }, { heading: "Name", path: "name" },
{ heading: 'Allowed IPs', path: 'allowed_ips' }, { heading: "Allowed IPs", path: "allowed_ips" },
{ heading: 'Endpoint', path: 'endpoint' }, { heading: "Endpoint", path: "endpoint" },
{ heading: 'Persistent Keepalive', path: 'persistent_keepalive' }, { heading: "Persistent Keepalive", path: "persistent_keepalive" },
{ heading: 'Comment', path: 'comment' }, { heading: "Comment", path: "comment" },
]; ];
const displayData = $computed(() => { const displayData = $computed(() => {
@ -32,24 +32,24 @@ const displayData = $computed(() => {
async function load() { async function load() {
loading = true; loading = true;
let res = await apiCall('vpn.wireguard.peers.list', {}); let res = await apiCall("vpn.wireguard.peers.list", {});
if (res.Error === null) { if (res.Error === null) {
console.debug('peers', res.Data); console.debug("peers", res.Data);
peers = res.Data; peers = res.Data;
} else { } else {
console.debug('error', res); console.debug("error", res);
} }
loading = false; loading = false;
} }
async function deletePeer() { async function deletePeer() {
let res = await apiCall('vpn.wireguard.peers.delete', { let res = await apiCall("vpn.wireguard.peers.delete", {
name: displayData[selection[0]].name, name: displayData[selection[0]].name,
}); });
if (res.Error === null) { if (res.Error === null) {
console.debug('deleted peer'); console.debug("deleted peer");
} else { } else {
console.debug('error', res); console.debug("error", res);
} }
load(); load();
} }
@ -76,9 +76,7 @@ onMounted(async () => {
> >
<button @click="load">Refresh</button> <button @click="load">Refresh</button>
<router-link class="button" to="/vpn/wireguard.peers/edit" <router-link class="button" to="/vpn/wireguard.peers/edit"
> >Create</router-link
Create
</router-link
> >
<button :disabled="selection.length != 1" @click="editPeer"> <button :disabled="selection.length != 1" @click="editPeer">
Edit Edit

View file

@ -15,10 +15,5 @@ export function isNullish(value: any) {
return (value === null || value === undefined); return (value === null || value === undefined);
} }
export function variantOf(enumValue: any) {
if (typeof enumValue === 'string') return enumValue;
else return Object.entries(enumValue)[0][0];
}
export type Index = string | number | symbol; export type Index = string | number | symbol;
export type MaybeIndex = Index | null; export type MaybeIndex = Index | null;