This commit is contained in:
adro 2023-11-01 09:28:34 +01:00
commit 277753dde5
28 changed files with 353 additions and 128 deletions

View file

@ -22,19 +22,19 @@ const NavStateCount = 3;
let navState = $ref(NavState.Open); let navState = $ref(NavState.Open);
const navRoutes = { const navRoutes = {
'/': { icon: IDashboard, caption: 'Dashboard' }, '/': { icon: IDashboard, caption: 'Dashboard' },
'/firewall/forwardrules': { icon: IRule, caption: 'Rules' }, '/firewall/forward_rules': { icon: IRule, caption: 'Rules' },
'/firewall/sourcenatrules': { icon: ISNAT, caption: 'SNAT' }, '/firewall/source_nat_rules': { icon: ISNAT, caption: 'SNAT' },
'/firewall/destinationnatrules': { icon: IDNAT, caption: 'DNAT' }, '/firewall/destination_nat_rules': { icon: IDNAT, caption: 'DNAT' },
'/network/interfaces': { icon: IEthernet, caption: 'Interfaces' }, '/network/interfaces': { icon: IEthernet, caption: 'Interfaces' },
'/network/staticroutes': { icon: IStaticRoutes, caption: 'Static Routes' }, '/network/static_routes': { icon: IStaticRoutes, caption: 'Static Routes' },
'/object/addresses': { icon: IAddress, caption: 'Addresses' }, '/object/addresses': { icon: IAddress, caption: 'Addresses' },
'/object/services': { icon: IService, caption: 'Services' }, '/object/services': { icon: IService, caption: 'Services' },
'/service/dhcpservers': { icon: IDHCPServer, caption: 'DHCP Server' }, '/service/dhcp_servers': { icon: IDHCPServer, caption: 'DHCP Server' },
'/service/dnsservers': { icon: IDNSServer, caption: 'DNS Server' }, '/service/dns_servers': { icon: IDNSServer, caption: 'DNS Server' },
'/service/ntpservers': { icon: ITimeServer, caption: 'NTP Server' }, '/service/ntp_servers': { icon: ITimeServer, caption: 'NTP Server' },
'/vpn/wireguardstatus': { icon: IWireguard, caption: 'Wireguard Status' }, '/vpn/wireguard_status': { icon: IWireguard, caption: 'Wireguard Status' },
'/vpn/wireguardinterfaces': { icon: IWireguard, caption: 'Wireguard Interfaces' }, '/vpn/wireguard_interfaces': { icon: IWireguard, caption: 'Wireguard Interfaces' },
'/vpn/wireguardpeers': { icon: IWireguard, caption: 'Wireguard Peers' }, '/vpn/wireguard_peers': { icon: IWireguard, caption: 'Wireguard Peers' },
'/system/users': { icon: IUser, caption: 'Users' }, '/system/users': { icon: IUser, caption: 'Users' },
'/config/config': { icon: IConfig, caption: 'Config' }, '/config/config': { icon: IConfig, caption: 'Config' },
}; };

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(`${editTypes[subsystem].name }.get_${ editTypes[subsystem][entity].name}`, {id: id as number - 0}); res = await apiCall(`${subsystem }.${entity}.get`, {id: id as number - 0});
} else { } else {
res = await apiCall(`${editTypes[subsystem].name }.get_${ editTypes[subsystem][entity].name}`, {id: id}); res = await apiCall(`${subsystem }.${entity}.get`, {id: id});
} }
if (res.Error === null) { if (res.Error === null) {
@ -30,7 +30,7 @@ async function load(){
async function update(value: any) { async function update(value: any) {
console.debug('value', value); console.debug('value', value);
let res = await apiCall(`${editTypes[subsystem].name }.update_${ editTypes[subsystem][entity].name}`, value); let res = await apiCall(`${subsystem}.${entity}.update`, value);
if (res.Error === null) { if (res.Error === null) {
p.toast.success(`Updated ${ editTypes[subsystem][entity].name}`); p.toast.success(`Updated ${ editTypes[subsystem][entity].name}`);
p.router.go(-1); p.router.go(-1);

View file

@ -9,7 +9,7 @@ const { subsystem, entity } = $(props);
async function create(value: any) { async function create(value: any) {
console.debug('value', value); console.debug('value', value);
let res = await apiCall(`${editTypes[subsystem].name }.create_${ editTypes[subsystem][entity].name}`, value); let res = await apiCall(`${subsystem}.${entity}.create`, value);
if (res.Error === null) { if (res.Error === null) {
p.toast.success(`Created ${ editTypes[subsystem][entity].name}`); p.toast.success(`Created ${ editTypes[subsystem][entity].name}`);
p.router.go(-1); p.router.go(-1);

View file

@ -28,7 +28,7 @@ const displayData = $computed(() => {
async function load(){ async function load(){
loading = true; loading = true;
let res = await apiCall('config.get_pending_changelog', {}); let res = await apiCall('config.pending_changes.log', {});
if (res.Error === null) { if (res.Error === null) {
console.debug('changelog', res.Data); console.debug('changelog', res.Data);
changelog = res.Data; changelog = res.Data;
@ -39,7 +39,7 @@ async function load(){
} }
async function apply(){ async function apply(){
let res = await apiCall('config.apply_pending_changes', {}); let res = await apiCall('config.pending_changes.apply', {});
if (res.Error === null) { if (res.Error === null) {
console.debug('apply'); console.debug('apply');
p.toast.success('Applied Pending Config'); p.toast.success('Applied Pending Config');
@ -50,7 +50,7 @@ async function apply(){
} }
async function discard(){ async function discard(){
let res = await apiCall('config.discard_pending_changes', {}); let res = await apiCall('config.pending_changes.discard', {});
if (res.Error === null) { if (res.Error === null) {
console.debug('discard'); console.debug('discard');
p.toast.success('Discarded Pending Config'); p.toast.success('Discarded Pending Config');

View file

@ -19,7 +19,7 @@ const columns = [
]; ];
async function load(){ async function load(){
let res = await apiCall('firewall.get_destination_nat_rules', {}); let res = await apiCall('firewall.destination_nat_rules.list', {});
if (res.Error === null) { if (res.Error === null) {
rules = res.Data; rules = res.Data;
console.debug('rules', rules); console.debug('rules', rules);
@ -29,7 +29,7 @@ async function load(){
} }
async function deleteRule(){ async function deleteRule(){
let res = await apiCall('firewall.delete_destination_nat_rule', {index: 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.move_destination_nat_rule', {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');
@ -61,8 +61,8 @@ onMounted(async() => {
<div> <div>
<TableView title="DNAT Rules" :columns="columns" :loading="loading" @dragged-row="draggedRow" v-model:selection="selection" v-model:data="rules" :table-props="{sort:true, sortSelf: true, draggable: true}"> <TableView title="DNAT Rules" :columns="columns" :loading="loading" @dragged-row="draggedRow" v-model:selection="selection" v-model:data="rules" :table-props="{sort:true, sortSelf: true, draggable: true}">
<button @click="load">Refresh</button> <button @click="load">Refresh</button>
<router-link class="button" to="/firewall/destinationnatrules/edit">Create</router-link> <router-link class="button" to="/firewall/destination_nat_rules/edit">Create</router-link>
<router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/firewall/destinationnatrules/edit/' + selection[0]">Edit</router-link> <router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/firewall/destination_nat_rules/edit/' + selection[0]">Edit</router-link>
<button @click="deleteRule" :disabled="selection.length != 1">Delete</button> <button @click="deleteRule" :disabled="selection.length != 1">Delete</button>
</TableView> </TableView>
</div> </div>

View file

@ -18,7 +18,7 @@ const columns = [
]; ];
async function load(){ async function load(){
let res = await apiCall('firewall.get_forward_rules', {}); let res = await apiCall('firewall.forward_rules.list', {});
if (res.Error === null) { if (res.Error === null) {
rules = res.Data; rules = res.Data;
console.debug('rules', rules); console.debug('rules', rules);
@ -28,7 +28,7 @@ async function load(){
} }
async function deleteRule(){ async function deleteRule(){
let res = await apiCall('firewall.delete_forward_rule', {index: 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');
@ -40,7 +40,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.move_forward_rule', {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');
@ -60,8 +60,8 @@ onMounted(async() => {
<div> <div>
<TableView title="Forward Rules" :columns="columns" :loading="loading" @dragged-row="draggedRow" v-model:selection="selection" v-model:data="rules" :table-props="{sort:true, sortSelf: true, draggable: true}"> <TableView title="Forward Rules" :columns="columns" :loading="loading" @dragged-row="draggedRow" v-model:selection="selection" v-model:data="rules" :table-props="{sort:true, sortSelf: true, draggable: true}">
<button @click="load">Refresh</button> <button @click="load">Refresh</button>
<router-link class="button" to="/firewall/forwardrules/edit">Create</router-link> <router-link class="button" to="/firewall/forward_rules/edit">Create</router-link>
<router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/firewall/forwardrules/edit/' + selection[0]">Edit</router-link> <router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/firewall/forward_rules/edit/' + selection[0]">Edit</router-link>
<button @click="deleteRule" :disabled="selection.length != 1">Delete</button> <button @click="deleteRule" :disabled="selection.length != 1">Delete</button>
</TableView> </TableView>
</div> </div>

View file

@ -19,7 +19,7 @@ const columns = [
]; ];
async function load(){ async function load(){
let res = await apiCall('firewall.get_source_nat_rules', {}); let res = await apiCall('firewall.source_nat_rules.list', {});
if (res.Error === null) { if (res.Error === null) {
rules = res.Data; rules = res.Data;
console.debug('rules', rules); console.debug('rules', rules);
@ -29,7 +29,7 @@ async function load(){
} }
async function deleteRule(){ async function deleteRule(){
let res = await apiCall('firewall.delete_source_nat:rule', {index: 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.move_source_nat_rule', {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');
@ -61,8 +61,8 @@ onMounted(async() => {
<div> <div>
<TableView title="SNAT Rules" :columns="columns" :loading="loading" @dragged-row="draggedRow" v-model:selection="selection" v-model:data="rules" :table-props="{sort:true, sortSelf: true, draggable: true}"> <TableView title="SNAT Rules" :columns="columns" :loading="loading" @dragged-row="draggedRow" v-model:selection="selection" v-model:data="rules" :table-props="{sort:true, sortSelf: true, draggable: true}">
<button @click="load">Refresh</button> <button @click="load">Refresh</button>
<router-link class="button" to="/firewall/sourcenatrules/edit">Create</router-link> <router-link class="button" to="/firewall/source_nat_rules/edit">Create</router-link>
<router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/firewall/sourcenatrules/edit/' + selection[0]">Edit</router-link> <router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/firewall/source_nat_rules/edit/' + selection[0]">Edit</router-link>
<button @click="deleteRule" :disabled="selection.length != 1">Delete</button> <button @click="deleteRule" :disabled="selection.length != 1">Delete</button>
</TableView> </TableView>
</div> </div>

View file

@ -12,7 +12,7 @@ let loading = $ref(false);
async function load(){ async function load(){
loading = true; loading = true;
let res = await apiCall('network.get_links', {}); let res = await apiCall('network.links.get', {});
if (res.Error === null) { if (res.Error === null) {
console.debug('links', res.Data); console.debug('links', res.Data);
links = res.Data; links = res.Data;

View file

@ -32,7 +32,7 @@ const displayData = $computed(() => {
async function load(){ async function load(){
loading = true; loading = true;
let res = await apiCall('network.get_interfaces', {}); let res = await apiCall('network.interfaces.list', {});
if (res.Error === null) { if (res.Error === null) {
console.debug('interfaces', res.Data); console.debug('interfaces', res.Data);
interfaces = res.Data; interfaces = res.Data;
@ -43,7 +43,7 @@ async function load(){
} }
async function deleteInterface(){ async function deleteInterface(){
let res = await apiCall('network.delete_interface', {name: displayData[selection[0]].name}); let res = await apiCall('network.interfaces.delete', {id: displayData[selection[0]].name});
if (res.Error === null) { if (res.Error === null) {
console.debug('deleted interface'); console.debug('deleted interface');
} else { } else {

View file

@ -15,7 +15,7 @@ const columns = [
async function load(){ async function load(){
loading = true; loading = true;
let res = await apiCall('network.get_static_routes', {}); let res = await apiCall('network.static_routes.list', {});
if (res.Error === null) { if (res.Error === null) {
console.debug('staticRoutes', res.Data); console.debug('staticRoutes', res.Data);
staticRoutes = res.Data; staticRoutes = res.Data;
@ -26,7 +26,7 @@ async function load(){
} }
async function deleteStaticRoutes(){ async function deleteStaticRoutes(){
let res = await apiCall('network.delete_static_route', {index: 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 {
@ -44,8 +44,8 @@ onMounted(async() => {
<template> <template>
<TableView title="Static Routes" :columns="columns" :loading="loading" v-model:selection="selection" v-model:data="staticRoutes" :table-props="{sort:true, sortSelf: true}"> <TableView title="Static Routes" :columns="columns" :loading="loading" v-model:selection="selection" v-model:data="staticRoutes" :table-props="{sort:true, sortSelf: true}">
<button @click="load">Refresh</button> <button @click="load">Refresh</button>
<router-link class="button" to="/network/staticroutes/edit">Create</router-link> <router-link class="button" to="/network/static_routes/edit">Create</router-link>
<router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/network/staticroutes/edit/' + selection[0]">Edit</router-link> <router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/network/static_routes/edit/' + selection[0]">Edit</router-link>
<button @click="deleteStaticRoutes" :disabled="selection.length != 1">Delete</button> <button @click="deleteStaticRoutes" :disabled="selection.length != 1">Delete</button>
</TableView> </TableView>
</template> </template>

View file

@ -16,7 +16,7 @@ const columns = [
async function load(){ async function load(){
loading = true; loading = true;
let res = await apiCall('object.get_addresses', {}); let res = await apiCall('object.addresses.list', {});
if (res.Error === null) { if (res.Error === null) {
addresses = res.Data; addresses = res.Data;
console.debug('addresses', addresses); console.debug('addresses', addresses);
@ -62,7 +62,7 @@ function getAddressValue(s: any): string {
} }
async function deleteAddress(){ async function deleteAddress(){
let res = await apiCall('object.delete_address', {name: 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

@ -56,7 +56,7 @@ function getServicePortRange(s:any): string {
async function load(){ async function load(){
loading = true; loading = true;
let res = await apiCall('object.get_services', {}); let res = await apiCall('object.services.list', {});
if (res.Error === null) { if (res.Error === null) {
console.debug('services', res.Data); console.debug('services', res.Data);
services = res.Data; services = res.Data;
@ -67,7 +67,7 @@ async function load(){
} }
async function deleteService(){ async function deleteService(){
let res = await apiCall('object.delete_service', {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

@ -13,7 +13,7 @@ const columns = [
]; ];
async function load(){ async function load(){
let res = await apiCall('service.get_dhcp_servers', {}); let res = await apiCall('service.dhcp_servers.list', {});
if (res.Error === null) { if (res.Error === null) {
servers = res.Data; servers = res.Data;
console.debug('rules', servers); console.debug('rules', servers);
@ -23,7 +23,7 @@ async function load(){
} }
async function deleteRule(){ async function deleteRule(){
let res = await apiCall('service.delete_dhcp_server', {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');
@ -41,10 +41,10 @@ onMounted(async() => {
<template> <template>
<div> <div>
<TableView title="DHCP v4 Servers" :columns="columns" :loading="loading" v-model:selection="selection" v-model:data="servers" :table-props="{sort:true, sortSelf: true}"> <TableView title="DHCP Servers" :columns="columns" :loading="loading" v-model:selection="selection" v-model:data="servers" :table-props="{sort:true, sortSelf: true}">
<button @click="load">Refresh</button> <button @click="load">Refresh</button>
<router-link class="button" to="/service/dhcpservers/edit">Create</router-link> <router-link class="button" to="/service/dhcp_servers/edit">Create</router-link>
<router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/service/dhcpservers/edit/' + selection[0]">Edit</router-link> <router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/service/dhcp_servers/edit/' + selection[0]">Edit</router-link>
<button @click="deleteRule" :disabled="selection.length != 1">Delete</button> <button @click="deleteRule" :disabled="selection.length != 1">Delete</button>
</TableView> </TableView>
</div> </div>

View file

@ -13,7 +13,7 @@ const columns = [
]; ];
async function load(){ async function load(){
let res = await apiCall('service.get_dns_servers', {}); let res = await apiCall('service.dns_servers.list', {});
if (res.Error === null) { if (res.Error === null) {
servers = res.Data; servers = res.Data;
console.debug('rules', servers); console.debug('rules', servers);
@ -23,7 +23,7 @@ async function load(){
} }
async function deleteRule(){ async function deleteRule(){
let res = await apiCall('service.delete_dns_server', {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');
@ -43,8 +43,8 @@ onMounted(async() => {
<div> <div>
<TableView title="DNS Servers" :columns="columns" :loading="loading" v-model:selection="selection" v-model:data="servers" :table-props="{sort:true, sortSelf: true}"> <TableView title="DNS Servers" :columns="columns" :loading="loading" v-model:selection="selection" v-model:data="servers" :table-props="{sort:true, sortSelf: true}">
<button @click="load">Refresh</button> <button @click="load">Refresh</button>
<router-link class="button" to="/service/dnsservers/edit">Create</router-link> <router-link class="button" to="/service/dns_servers/edit">Create</router-link>
<router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/service/dnsservers/edit/' + selection[0]">Edit</router-link> <router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/service/dns_servers/edit/' + selection[0]">Edit</router-link>
<button @click="deleteRule" :disabled="selection.length != 1">Delete</button> <button @click="deleteRule" :disabled="selection.length != 1">Delete</button>
</TableView> </TableView>
</div> </div>

View file

@ -13,7 +13,7 @@ const columns = [
]; ];
async function load(){ async function load(){
let res = await apiCall('service.get_ntp_servers', {}); let res = await apiCall('service.ntp_servers.list', {});
if (res.Error === null) { if (res.Error === null) {
servers = res.Data; servers = res.Data;
console.debug('rules', servers); console.debug('rules', servers);
@ -23,7 +23,7 @@ async function load(){
} }
async function deleteRule(){ async function deleteRule(){
let res = await apiCall('service.delete_ntp_server', {index: 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');
@ -43,8 +43,8 @@ onMounted(async() => {
<div> <div>
<TableView title="NTP Servers" :columns="columns" :loading="loading" v-model:selection="selection" v-model:data="servers" :table-props="{sort:true, sortSelf: true}"> <TableView title="NTP Servers" :columns="columns" :loading="loading" v-model:selection="selection" v-model:data="servers" :table-props="{sort:true, sortSelf: true}">
<button @click="load">Refresh</button> <button @click="load">Refresh</button>
<router-link class="button" to="/service/ntpservers/edit">Create</router-link> <router-link class="button" to="/service/ntp_servers/edit">Create</router-link>
<router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/service/ntpservers/edit/' + selection[0]">Edit</router-link> <router-link class="button" :class="{ disabled: selection.length != 1 }" :to="'/service/ntp_servers/edit/' + selection[0]">Edit</router-link>
<button @click="deleteRule" :disabled="selection.length != 1">Delete</button> <button @click="deleteRule" :disabled="selection.length != 1">Delete</button>
</TableView> </TableView>
</div> </div>

View file

@ -14,7 +14,7 @@ const columns = [
async function load(){ async function load(){
loading = true; loading = true;
let res = await apiCall('system.get_users', {}); let res = await apiCall('system.users.list', {});
if (res.Error === null) { if (res.Error === null) {
users = res.Data; users = res.Data;
console.debug('users', users); console.debug('users', users);
@ -25,7 +25,7 @@ async function load(){
} }
async function deleteUser(){ async function deleteUser(){
let res = await apiCall('system.delete_user', {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

@ -31,7 +31,7 @@ const displayData = $computed(() => {
async function load(){ async function load(){
loading = true; loading = true;
let res = await apiCall('vpn.wireguard.get_interfaces', {}); let res = await apiCall('vpn.wireguard.interfaces.list', {});
if (res.Error === null) { if (res.Error === null) {
console.debug('interfaces', res.Data); console.debug('interfaces', res.Data);
interfaces = res.Data; interfaces = res.Data;
@ -42,7 +42,7 @@ async function load(){
} }
async function deleteInterface(){ async function deleteInterface(){
let res = await apiCall('vpn.wireguard_delete_interface', {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 {
@ -52,7 +52,7 @@ async function deleteInterface(){
} }
async function editInterface() { async function editInterface() {
p.router.push(`/vpn/wireguardinterfaces/edit/${ displayData[selection[0]].name}`); p.router.push(`/vpn/wireguard_interfaces/edit/${ displayData[selection[0]].name}`);
} }
onMounted(async() => { onMounted(async() => {
@ -64,7 +64,7 @@ onMounted(async() => {
<template> <template>
<TableView title="Wireguard Interfaces" :columns="columns" :loading="loading" v-model:selection="selection" v-model:data="displayData" :table-props="{sort:true, sortSelf: true}"> <TableView title="Wireguard Interfaces" :columns="columns" :loading="loading" v-model:selection="selection" v-model:data="displayData" :table-props="{sort:true, sortSelf: true}">
<button @click="load">Refresh</button> <button @click="load">Refresh</button>
<router-link class="button" to="/vpn/wireguardinterfaces/edit">Create</router-link> <router-link class="button" to="/vpn/wireguard_interfaces/edit">Create</router-link>
<button @click="editInterface" :disabled="selection.length != 1">Edit</button> <button @click="editInterface" :disabled="selection.length != 1">Edit</button>
<button @click="deleteInterface" :disabled="selection.length != 1">Delete</button> <button @click="deleteInterface" :disabled="selection.length != 1">Delete</button>
</TableView> </TableView>

View file

@ -32,7 +32,7 @@ const displayData = $computed(() => {
async function load(){ async function load(){
loading = true; loading = true;
let res = await apiCall('vpn.wireguard.get_peers', {}); 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;
@ -43,7 +43,7 @@ async function load(){
} }
async function deletePeer(){ async function deletePeer(){
let res = await apiCall('vpn.wireguard.delete_peer', {name: displayData[selection[0]].name}); let res = await apiCall('vpn.wireguard.peers.delete', {name: displayData[selection[0]].name});
if (res.Error === null) { if (res.Error === null) {
console.debug('deleted peer'); console.debug('deleted peer');
} else { } else {
@ -53,7 +53,7 @@ async function deletePeer(){
} }
async function editPeer() { async function editPeer() {
p.router.push(`/vpn/wireguardpeers/edit/${ displayData[selection[0]].name}`); p.router.push(`/vpn/wireguard_peers/edit/${ displayData[selection[0]].name}`);
} }
onMounted(async() => { onMounted(async() => {
@ -65,7 +65,7 @@ onMounted(async() => {
<template> <template>
<TableView title="Peers" :columns="columns" :loading="loading" v-model:selection="selection" v-model:data="displayData" :table-props="{sort:true, sortSelf: true}"> <TableView title="Peers" :columns="columns" :loading="loading" v-model:selection="selection" v-model:data="displayData" :table-props="{sort:true, sortSelf: true}">
<button @click="load">Refresh</button> <button @click="load">Refresh</button>
<router-link class="button" to="/vpn/wireguardpeers/edit">Create</router-link> <router-link class="button" to="/vpn/wireguard_peers/edit">Create</router-link>
<button @click="editPeer" :disabled="selection.length != 1">Edit</button> <button @click="editPeer" :disabled="selection.length != 1">Edit</button>
<button @click="deletePeer" :disabled="selection.length != 1">Delete</button> <button @click="deletePeer" :disabled="selection.length != 1">Delete</button>
</TableView> </TableView>

View file

@ -6,7 +6,7 @@ let loading = $ref(false);
async function load() { async function load() {
loading = true; loading = true;
let res = await apiCall('vpn.wireguard.get_status', {}); let res = await apiCall('vpn.wireguard.status', {});
if (res.Error === null) { if (res.Error === null) {
console.debug('status', res.Data); console.debug('status', res.Data);
status = res.Data; status = res.Data;

View file

@ -9,15 +9,15 @@ use super::ApiError::ConfigError;
pub fn register_methods(module: &mut RpcModule<RpcState>) { pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method("config.get_pending_changelog", get_pending_changelog) .register_method("config.pending_changes.log", get_pending_changelog)
.unwrap(); .unwrap();
module module
.register_method("config.apply_pending_changes", apply_pending_changes) .register_method("config.pending_changes.apply", apply_pending_changes)
.unwrap(); .unwrap();
module module
.register_method("config.discard_pending_changes", discard_pending_changes) .register_method("config.pending_changes.discard", discard_pending_changes)
.unwrap(); .unwrap();
} }

View file

@ -1,7 +1,8 @@
use super::ApiError; use super::ApiError;
use crate::{ use crate::{
create_vec_thing,
definitions::firewall::{DestinationNATRule, ForwardRule, SourceNATRule}, definitions::firewall::{DestinationNATRule, ForwardRule, SourceNATRule},
get_things, get_vec_thing, delete_vec_thing, get_vec_thing, list_things,
state::RpcState, state::RpcState,
}; };
use jsonrpsee::RpcModule; use jsonrpsee::RpcModule;
@ -9,43 +10,85 @@ use jsonrpsee::RpcModule;
pub fn register_methods(module: &mut RpcModule<RpcState>) { pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method( .register_method(
"firewall.get_forward_rule", "firewall.forward_rules.get",
get_vec_thing!(firewall.forward_rules), get_vec_thing!(firewall.forward_rules),
) )
.unwrap(); .unwrap();
module module
.register_method::<Result<Vec<ForwardRule>, ApiError>, _>( .register_method::<Result<Vec<ForwardRule>, ApiError>, _>(
"firewall.get_forward_rules", "firewall.forward_rules.list",
get_things!(firewall.forward_rules), list_things!(firewall.forward_rules),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"firewall.get_destination_nat_rule", "firewall.forward_rules.create",
create_vec_thing!(firewall.forward_rules, ForwardRule),
)
.unwrap();
module
.register_method(
"firewall.forward_rules.delete",
delete_vec_thing!(firewall.forward_rules),
)
.unwrap();
module
.register_method(
"firewall.destination_nat_rules.get",
get_vec_thing!(firewall.destination_nat_rules), get_vec_thing!(firewall.destination_nat_rules),
) )
.unwrap(); .unwrap();
module module
.register_method::<Result<Vec<DestinationNATRule>, ApiError>, _>( .register_method::<Result<Vec<DestinationNATRule>, ApiError>, _>(
"firewall.get_destination_nat_rules", "firewall.destination_nat_rules.list",
get_things!(firewall.destination_nat_rules), list_things!(firewall.destination_nat_rules),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"firewall.get_source_nat_rule", "firewall.destination_nat_rules.create",
create_vec_thing!(firewall.destination_nat_rules, DestinationNATRule),
)
.unwrap();
module
.register_method(
"firewall.destination_nat_rules.delete",
delete_vec_thing!(firewall.destination_nat_rules),
)
.unwrap();
module
.register_method(
"firewall.source_nat_rules.get",
get_vec_thing!(firewall.source_nat_rules), get_vec_thing!(firewall.source_nat_rules),
) )
.unwrap(); .unwrap();
module module
.register_method::<Result<Vec<SourceNATRule>, ApiError>, _>( .register_method::<Result<Vec<SourceNATRule>, ApiError>, _>(
"firewall.get_source_nat_rules", "firewall.source_nat_rules.list",
get_things!(firewall.source_nat_rules), list_things!(firewall.source_nat_rules),
)
.unwrap();
module
.register_method(
"firewall.source_nat_rules.create",
create_vec_thing!(firewall.source_nat_rules, SourceNATRule),
)
.unwrap();
module
.register_method(
"firewall.source_nat_rules.delete",
delete_vec_thing!(firewall.source_nat_rules),
) )
.unwrap(); .unwrap();
} }

View file

@ -93,7 +93,7 @@ macro_rules! get_vec_thing {
} }
#[macro_export] #[macro_export]
macro_rules! get_things { macro_rules! list_things {
($( $sub_system:ident ).+) => { ($( $sub_system:ident ).+) => {
|_, state| { |_, state| {
Ok(state Ok(state
@ -104,6 +104,93 @@ macro_rules! get_things {
}; };
} }
#[macro_export]
macro_rules! create_vec_thing {
($( $sub_system:ident ).+, $typ:ty) => {
|params, state| {
let t: $typ = params.parse().map_err(ApiError::ParameterDeserialize)?;
let mut cm = state.config_manager.clone();
let mut tx = cm.start_transaction();
tx.config.$($sub_system).+.push(t);
let id = {tx.config.$($sub_system).+.len() - 1}.to_string();
tx.commit(crate::config_manager::Change {
action: crate::config_manager::ChangeAction::Delete,
path: stringify!($($sub_system).+),
id,
})
.map_err(ApiError::ConfigError)
}
};
}
#[macro_export]
macro_rules! delete_map_thing {
($( $sub_system:ident ).+) => {
|params, state| {
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize)]
struct GetStringID {
id: String,
}
let t: GetStringID = params.parse().map_err(ApiError::ParameterDeserialize)?;
let mut cm = state.config_manager.clone();
let mut tx = cm.start_transaction();
match tx.config.$($sub_system).+.remove(&t.id) {
Some(_) => tx
.commit(crate::config_manager::Change {
action: crate::config_manager::ChangeAction::Delete,
path: stringify!($($sub_system).+),
id: t.id,
})
.map_err(ApiError::ConfigError),
None => {
tx.revert();
Err(ApiError::NotFound)
}
}
}
};
}
#[macro_export]
macro_rules! delete_vec_thing {
($( $sub_system:ident ).+) => {
|params, state| {
use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize)]
struct GetIntID {
id: i64,
}
let t: GetIntID = params.parse().map_err(ApiError::ParameterDeserialize)?;
let mut cm = state.config_manager.clone();
let mut tx = cm.start_transaction();
if tx.config.$($sub_system).+.len() > t.id as usize {
tx.config.$($sub_system).+.remove(t.id as usize);
tx.commit(crate::config_manager::Change {
action: crate::config_manager::ChangeAction::Delete,
path: stringify!($($sub_system).+),
id: t.id.to_string(),
})
.map_err(ApiError::ConfigError)
} else {
tx.revert();
Err(ApiError::NotFound)
}
}
};
}
pub fn new_rpc_module(state: RpcState) -> RpcModule<RpcState> { pub fn new_rpc_module(state: RpcState) -> RpcModule<RpcState> {
let mut module = RpcModule::new(state); let mut module = RpcModule::new(state);

View file

@ -1,7 +1,8 @@
use super::ApiError; use super::ApiError;
use crate::{ use crate::{
create_vec_thing,
definitions::network::{NetworkInterface, StaticRoute}, definitions::network::{NetworkInterface, StaticRoute},
get_map_thing, get_things, get_vec_thing, delete_map_thing, delete_vec_thing, get_map_thing, get_vec_thing, list_things,
state::RpcState, state::RpcState,
}; };
use jsonrpsee::RpcModule; use jsonrpsee::RpcModule;
@ -10,26 +11,47 @@ use std::collections::HashMap;
pub fn register_methods(module: &mut RpcModule<RpcState>) { pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method( .register_method(
"network.get_static_route", "network.static_routes.get",
get_vec_thing!(network.static_routes), get_vec_thing!(network.static_routes),
) )
.unwrap(); .unwrap();
module module
.register_method::<Result<Vec<StaticRoute>, ApiError>, _>( .register_method::<Result<Vec<StaticRoute>, ApiError>, _>(
"network.get_static_routes", "network.static_routes.list",
get_things!(network.static_routes), list_things!(network.static_routes),
) )
.unwrap(); .unwrap();
module module
.register_method("network.get_interface", get_map_thing!(network.interfaces)) .register_method(
"network.static_routes.create",
create_vec_thing!(network.static_routes, StaticRoute),
)
.unwrap();
module
.register_method(
"network.static_routes.delete",
delete_vec_thing!(network.static_routes),
)
.unwrap();
module
.register_method("network.interfaces.get", get_map_thing!(network.interfaces))
.unwrap(); .unwrap();
module module
.register_method::<Result<HashMap<String, NetworkInterface>, ApiError>, _>( .register_method::<Result<HashMap<String, NetworkInterface>, ApiError>, _>(
"network.get_interfaces", "network.interfaces.list",
get_things!(network.interfaces), list_things!(network.interfaces),
)
.unwrap();
module
.register_method(
"network.interfaces.delete",
delete_map_thing!(network.interfaces),
) )
.unwrap(); .unwrap();
} }

View file

@ -1,7 +1,7 @@
use super::ApiError; use super::ApiError;
use crate::{ use crate::{
definitions::object::{Address, Service}, definitions::object::{Address, Service},
get_map_thing, get_things, delete_map_thing, get_map_thing, list_things,
state::RpcState, state::RpcState,
}; };
use jsonrpsee::RpcModule; use jsonrpsee::RpcModule;
@ -9,24 +9,35 @@ use std::collections::HashMap;
pub fn register_methods(module: &mut RpcModule<RpcState>) { pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method("object.get_service", get_map_thing!(object.services)) .register_method("object.services.get", get_map_thing!(object.services))
.unwrap(); .unwrap();
module module
.register_method::<Result<HashMap<String, Service>, ApiError>, _>( .register_method::<Result<HashMap<String, Service>, ApiError>, _>(
"object.get_services", "object.services.list",
get_things!(object.services), list_things!(object.services),
) )
.unwrap(); .unwrap();
module module
.register_method("object.get_address", get_map_thing!(object.addresses)) .register_method("object.services.delete", delete_map_thing!(object.services))
.unwrap();
module
.register_method("object.addresses.get", get_map_thing!(object.addresses))
.unwrap(); .unwrap();
module module
.register_method::<Result<HashMap<String, Address>, ApiError>, _>( .register_method::<Result<HashMap<String, Address>, ApiError>, _>(
"object.get_addresses", "object.addresses.list",
get_things!(object.addresses), list_things!(object.addresses),
)
.unwrap();
module
.register_method(
"object.addresses.delete",
delete_map_thing!(object.addresses),
) )
.unwrap(); .unwrap();
} }

View file

@ -1,7 +1,8 @@
use super::ApiError; use super::ApiError;
use crate::{ use crate::{
create_vec_thing,
definitions::service::{DHCPServer, DNSServer, NTPServer}, definitions::service::{DHCPServer, DNSServer, NTPServer},
get_things, get_vec_thing, delete_vec_thing, get_vec_thing, list_things,
state::RpcState, state::RpcState,
}; };
use jsonrpsee::RpcModule; use jsonrpsee::RpcModule;
@ -9,43 +10,85 @@ use jsonrpsee::RpcModule;
pub fn register_methods(module: &mut RpcModule<RpcState>) { pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method( .register_method(
"service.get_dhcp_server", "service.dhcp_servers.get",
get_vec_thing!(service.dhcp_servers), get_vec_thing!(service.dhcp_servers),
) )
.unwrap(); .unwrap();
module module
.register_method::<Result<Vec<DHCPServer>, ApiError>, _>( .register_method::<Result<Vec<DHCPServer>, ApiError>, _>(
"service.get_dhcp_servers", "service.dhcp_servers.list",
get_things!(service.dhcp_servers), list_things!(service.dhcp_servers),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"service.get_dns_server", "service.dhcp_servers.create",
create_vec_thing!(service.dhcp_servers, DHCPServer),
)
.unwrap();
module
.register_method(
"service.dhcp_servers.delete",
delete_vec_thing!(service.dhcp_servers),
)
.unwrap();
module
.register_method(
"service.dns_servers.get",
get_vec_thing!(service.dns_servers), get_vec_thing!(service.dns_servers),
) )
.unwrap(); .unwrap();
module module
.register_method::<Result<Vec<DNSServer>, ApiError>, _>( .register_method::<Result<Vec<DNSServer>, ApiError>, _>(
"service.get_dns_servers", "service.dns_servers.list",
get_things!(service.dns_servers), list_things!(service.dns_servers),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"service.get_ntp_server", "service.dns_servers.create",
create_vec_thing!(service.dns_servers, DNSServer),
)
.unwrap();
module
.register_method(
"service.dns_servers.delete",
delete_vec_thing!(service.dns_servers),
)
.unwrap();
module
.register_method(
"service.ntp_servers.get",
get_vec_thing!(service.ntp_servers), get_vec_thing!(service.ntp_servers),
) )
.unwrap(); .unwrap();
module module
.register_method::<Result<Vec<NTPServer>, ApiError>, _>( .register_method::<Result<Vec<NTPServer>, ApiError>, _>(
"service.get_ntp_servers", "service.ntp_servers.list",
get_things!(service.ntp_servers), list_things!(service.ntp_servers),
)
.unwrap();
module
.register_method(
"service.ntp_servers.create",
create_vec_thing!(service.ntp_servers, NTPServer),
)
.unwrap();
module
.register_method(
"service.ntp_servers.delete",
delete_vec_thing!(service.ntp_servers),
) )
.unwrap(); .unwrap();
} }

View file

@ -17,22 +17,24 @@ use super::ApiError;
const USER_CHANGE_PATH: &str = "system.user"; const USER_CHANGE_PATH: &str = "system.user";
pub fn register_methods(module: &mut RpcModule<RpcState>) { pub fn register_methods(module: &mut RpcModule<RpcState>) {
module.register_method("system.get_user", get_user).unwrap();
module module
.register_method("system.get_users", get_users) .register_method("system.users.get", get_user)
.unwrap(); .unwrap();
module module
.register_method("system.create_user", create_user) .register_method("system.users.list", get_users)
.unwrap(); .unwrap();
module module
.register_method("system.update_user", update_user) .register_method("system.users.create", create_user)
.unwrap(); .unwrap();
module module
.register_method("system.delete_user", delete_user) .register_method("system.users.update", update_user)
.unwrap();
module
.register_method("system.users.delete", delete_user)
.unwrap(); .unwrap();
} }

View file

@ -3,44 +3,58 @@ use std::collections::HashMap;
use super::ApiError; use super::ApiError;
use crate::definitions::vpn::{WireguardInterface, WireguardPeer}; use crate::definitions::vpn::{WireguardInterface, WireguardPeer};
use crate::state::RpcState; use crate::state::RpcState;
use crate::{get_map_thing, get_things}; use crate::{delete_map_thing, get_map_thing, list_things};
use jsonrpsee::types::Params; use jsonrpsee::types::Params;
use jsonrpsee::RpcModule; use jsonrpsee::RpcModule;
pub fn register_methods(module: &mut RpcModule<RpcState>) { pub fn register_methods(module: &mut RpcModule<RpcState>) {
module module
.register_method("vpn.wireguard.get_status", get_wireguard_status) .register_method("vpn.wireguard.status", wireguard_status)
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"vpn.wireguard.get_interface", "vpn.wireguard.interfaces.get",
get_map_thing!(vpn.wireguard.interfaces), get_map_thing!(vpn.wireguard.interfaces),
) )
.unwrap(); .unwrap();
module module
.register_method::<Result<HashMap<String, WireguardInterface>, ApiError>, _>( .register_method::<Result<HashMap<String, WireguardInterface>, ApiError>, _>(
"vpn.wireguard.get_interfaces", "vpn.wireguard.interfaces.list",
get_things!(vpn.wireguard.interfaces), list_things!(vpn.wireguard.interfaces),
) )
.unwrap(); .unwrap();
module module
.register_method( .register_method(
"vpn.wireguard.get_peer", "vpn.wireguard.interfaces.delete",
delete_map_thing!(vpn.wireguard.interfaces),
)
.unwrap();
module
.register_method(
"vpn.wireguard.peers.get",
get_map_thing!(vpn.wireguard.peers), get_map_thing!(vpn.wireguard.peers),
) )
.unwrap(); .unwrap();
module module
.register_method::<Result<HashMap<String, WireguardPeer>, ApiError>, _>( .register_method::<Result<HashMap<String, WireguardPeer>, ApiError>, _>(
"vpn.wireguard.get_peers", "vpn.wireguard.peers.list",
get_things!(vpn.wireguard.peers), list_things!(vpn.wireguard.peers),
)
.unwrap();
module
.register_method(
"vpn.wireguard.peers.delete",
delete_map_thing!(vpn.wireguard.peers),
) )
.unwrap(); .unwrap();
} }
pub fn get_wireguard_status(_: Params, _: &RpcState) -> Result<String, ApiError> { pub fn wireguard_status(_: Params, _: &RpcState) -> Result<String, ApiError> {
Ok("ok".to_string()) Ok("ok".to_string())
} }

View file

@ -34,16 +34,12 @@ pub struct Service {
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum ServiceType { pub enum ServiceType {
TCP { TCP {
source_port: u64, source: PortDefinition,
source_port_end: Option<u64>, destination: PortDefinition,
destination_port: u64,
destination_port_end: Option<u64>,
}, },
UDP { UDP {
source_port: u64, source: PortDefinition,
source_port_end: Option<u64>, destination: PortDefinition,
destination_port: u64,
destination_port_end: Option<u64>,
}, },
ICMP { ICMP {
code: u8, code: u8,
@ -52,3 +48,10 @@ pub enum ServiceType {
children: Vec<String>, children: Vec<String>,
}, },
} }
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "snake_case")]
pub enum PortDefinition {
Single { port: u64 },
Range { start_port: u64, end_port: u64 },
}