role add, edit, main page

This commit is contained in:
core 2023-09-26 00:13:00 -04:00
parent 918a3ad1ea
commit 80c1250ec7
Signed by: core
GPG Key ID: FDBF740DADDCEECF
9 changed files with 336 additions and 168 deletions

View File

@ -1,12 +0,0 @@
<script lang="ts">
import {t} from "svelte-i18n";
export let selected;
</script>
<div>
<button disabled="{selected === 'hosts'}" on:click={() => {window.location.href="/hosts"}}>{$t("common.page.hosts")}</button>
<button disabled="{selected === 'lighthouses'}" on:click={() => {window.location.href="/lighthouses"}}>{$t("common.page.lighthouses")}</button>
<button disabled="{selected === 'relays'}" on:click={() => {window.location.href="/relays"}}>{$t("common.page.relays")}</button>
<button disabled="{selected === 'roles'}" on:click={() => {window.location.href="/roles"}}>{$t("common.page.roles")}</button>
</div>

View File

@ -0,0 +1,53 @@
<script lang="ts">
import {t} from "svelte-i18n";
export let selected;
</script>
<div class=" container h-100 w-100">
<div class="d-flex flex-column flex-shrink-0 p-3 h-100 bg-dark col position-absolute" style="width: 300px; left: 0; top: 0;">
<p class="d-flex align-items-center mb-3 mb-md-0 me-md-auto text-white text-decoration-none ml-5 fs-4">
<i class="fas fa-satellite fa-fw bi me-2"></i>
Trifid
</p>
<hr>
<ul class="nav nav-pills flex-column mb-auto">
<li class="nav-item">
<a class="nav-link py-2 px-4" class:active={selected === 'hosts'} href="/hosts">
<i class="bi me-2 fas fa-computer fa-fw"></i>
{$t("common.page.hosts")}
</a>
</li>
<li class="nav-item">
<a class="nav-link py-2 px-4" class:active={selected === 'lighthouses'} href="/lighthouses">
<i class="bi me-2 fas fa-server fa-fw"></i>
{$t("common.page.lighthouses")}
</a>
</li>
<li class="nav-item">
<a class="nav-link py-2 px-4" class:active={selected === 'relays'} href="/relays">
<i class="bi me-2 fas fa-network-wired fa=fw"></i>
{$t("common.page.relays")}
</a>
</li>
<li class="nav-item">
<a class="nav-link py-2 px-4" class:active={selected === 'roles'} href="/roles">
<i class="bi me-2 fas fa-address-book fa-fw"></i>
{$t("common.page.roles")}
</a>
</li>
</ul>
<hr>
<div class="nav-item">
<button class="nav-link py-2 px-4" on:click={() => {window.localStorage.setItem("mfa", "")}}>
<i class="me-2 fas fa-right-from-bracket fa-fw"></i>
{$t("common.logout")}
</button>
</div>
</div>
<div class="col p-3">
<slot></slot>
</div>
</div>

View File

@ -1,5 +1,6 @@
<script lang="ts">
import {logDeltaReset, Logger, logSetup} from "$lib/logger";
import {t} from "svelte-i18n";
export let isLoading;
export let isError;
@ -19,10 +20,22 @@
</script>
{#if isLoading}
<h1>its loading</h1>
<div class="h-100 d-flex align-items-center justify-content-center">
<div class="card">
<div class="card-body text-center">
<h4 class="card-title mb-0">{$t("common.loading")} <i class="fas fa-gear fa-spin"></i></h4>
</div>
</div>
</div>
{:else}
{#if isError}
<h1>error: {error}</h1>
<div class="h-100 d-flex align-items-center justify-content-center">
<div class="card w-25">
<div class="card-body text-center">
<h4 class="card-title mb-0 text-danger">{error}</h4>
</div>
</div>
</div>
{:else}
<slot></slot>
{/if}

View File

@ -91,9 +91,8 @@
"rules": "Rule count",
"description": "Description",
"actions": "Actions",
"editbtn": "Edit",
"delete": "Delete",
"add": {
"title": "Create Role",
"any": "Any",
"name": "Role name",
"desc": "Role description",
@ -105,10 +104,9 @@
"description": "Description",
"protocol": "Protocol",
"portrange": "Port range",
"allowedrole": "Allowed role"
"allowedrole": "Allowed role",
"actions": "Actions"
},
"ruleremove": "Remove rule",
"ruleedit": "Edit rule",
"rulesadd": "Add rule",
"editrule": {
"protocol": "Protocol",
@ -118,9 +116,13 @@
"add": "Add rule",
"edit": "Save edit",
"cancel": "Cancel"
},
"error": {
"needsname": "Role Name is required"
}
},
"edit": {
"title": "Editing rule {rule}",
"any": "Any",
"name": "Role name",
"desc": "Role description",
@ -162,6 +164,8 @@
"roles": "Roles",
"lighthouses": "Lighthouses",
"relays": "Relays"
}
},
"logout": "Log out",
"loading": "Dashboard is loading"
}
}

View File

@ -2,10 +2,14 @@
import "bootswatch/dist/darkly/bootstrap.css";
import "@fortawesome/fontawesome-free/css/all.css";
import "@fortawesome/fontawesome-free/js/all.js";
import "@popperjs/core";
import {onMount} from "svelte";
onMount(async () => {
await import("bootstrap/dist/js/bootstrap.js");
const bootstrap = await import("bootstrap/dist/js/bootstrap.js");
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl))
})
</script>

View File

@ -7,7 +7,7 @@
import type {APIError} from "$lib/auth.ts";
import {PUBLIC_BASE_URL} from "$env/static/public";
import {Configuration, NetworksApi} from "$lib/api";
import AdminBar from "$components/AdminBar.svelte";
import AdminLayout from "$components/AdminLayout.svelte";
let loading = true;
let isError = false;
@ -72,6 +72,7 @@
</svelte:head>
<LoadingWrapper isLoading={currentlyLoading} isError={isError} error={error}>
<AdminBar selected="hosts" />
<h1>its not loading anymore</h1>
<AdminLayout selected="hosts">
<h3>{$t("common.page.hosts")}</h3>
</AdminLayout>
</LoadingWrapper>

View File

@ -7,7 +7,7 @@
import type {APIError} from "$lib/auth.ts";
import {PUBLIC_BASE_URL} from "$env/static/public";
import {Configuration, NetworksApi, RolesApi} from "$lib/api";
import AdminBar from "$components/AdminBar.svelte";
import AdminLayout from "$components/AdminLayout.svelte";
let loading = true;
let isError = false;
@ -100,23 +100,26 @@
</svelte:head>
<LoadingWrapper isLoading={currentlyLoading} isError={isError} error={error}>
<AdminBar selected="roles" />
<h1>{$t("common.page.roles")}</h1>
<button on:click={roleAdd}>{$t("roles.create")}</button>
<AdminLayout selected="roles">
<div class="block">
<h3 class="inline">{$t("common.page.roles")} <button class="inline float-end btn btn-primary" on:click={roleAdd}>{$t("roles.create")} <i class="bi ms-1 fas fa-add"></i></button></h3>
</div>
<p>{$t("roles.explain")}</p>
{#if (roles.data.length === 0)}
<p>{$t("roles.noroles")}</p>
{:else}
<table>
<table class="table table-dark table-hover">
<thead>
<tr>
<th>{$t("roles.name")}</th>
<th>{$t("roles.rules")}</th>
<th>{$t("roles.description")}</th>
<th>{$t("roles.actions")}</th>
<th scope="col">{$t("roles.name")}</th>
<th scope="col">{$t("roles.rules")}</th>
<th scope="col">{$t("roles.description")}</th>
<th scope="col">{$t("roles.actions")}</th>
</tr>
</thead>
<tbody>
{#each roles.data as role}
<tr>
<td>
@ -127,11 +130,16 @@
<td>{role.firewallRules.length}</td>
<td>{role.description}</td>
<td>
<button on:click={() => {window.location.href = `/roles/${role.id}/edit`}}>{$t("roles.editbtn")}</button>
<button on:click={() => {roleDelete(role.id)}}>{$t("roles.delete")}</button>
<div class="btn-group">
<button class="btn btn-primary" on:click={() => {window.location.href = `/roles/${role.id}/edit`}}><i class="fas fa-pencil fa-fw"></i></button>
<button class="btn btn-danger" on:click={() => {roleDelete(role.id)}}><i class="fas fa-trash fa-fw"></i></button>
</div>
</td>
</tr>
{/each}
</tbody>
</table>
{/if}
</AdminLayout>
</LoadingWrapper>

View File

@ -8,8 +8,9 @@
import {PUBLIC_BASE_URL} from "$env/static/public";
import {Configuration, NetworksApi, RolesApi, FirewallRuleProtocolEnum} from "$lib/api";
import type {FirewallRule} from "$lib/api";
import AdminBar from "$components/AdminBar.svelte";
import AdminBar from "$components/AdminLayout.svelte";
import {page} from "$app/stores";
import AdminLayout from "$components/AdminLayout.svelte";
let loading = true;
let isError = false;
@ -24,6 +25,8 @@
let roleName = '';
let roleDescription = '';
let formErr = '';
let hasFormErr = false;
enum RuleProtocol {
ANY = 0,
@ -211,6 +214,7 @@
}
async function roleEdit() {
loading = true;
const configuration = new Configuration({
basePath: PUBLIC_BASE_URL,
accessToken: window.localStorage.getItem("session") + " " + window.localStorage.getItem("mfa")
@ -346,66 +350,106 @@
</svelte:head>
<LoadingWrapper isLoading={currentlyLoading} isError={isError} error={error}>
<AdminBar selected="roles" />
<form on:submit|preventDefault={roleEdit}>
<label for="roleName">{$t("roles.edit.name")}</label>
<input disabled bind:value={roleName} type="text" id="roleName" />
<label for="roleDesc">{$t("roles.edit.desc")}</label>
<input bind:value={roleDescription} type="text" id="roleDesc" />
<h3>{$t("roles.edit.rules")}</h3>
<AdminLayout selected="roles">
<h3>{$t("roles.edit.title", {values: {rule: roleName}})}</h3>
<form>
<label class="mt-2 form-label" for="roleDesc">{$t("roles.edit.desc")}</label>
<input class="form-control" bind:value={roleDescription} type="text" id="roleDesc" />
<hr>
<h5>{$t("roles.edit.rules")}</h5>
<p>{$t("roles.edit.rulesexplainer")}</p>
<!-- firewall rules -->
<table>
<table class="table table-dark rounded-2 table-hover">
<thead>
<tr>
<th>{$t("roles.edit.rulescols.description")}</th>
<th>{$t("roles.edit.rulescols.protocol")}</th>
<th>{$t("roles.edit.rulescols.portrange")}</th>
<th>{$t("roles.edit.rulescols.allowedrole")}</th>
<th scope="col">{$t("roles.edit.rulescols.description")}</th>
<th scope="col">{$t("roles.edit.rulescols.protocol")}</th>
<th scope="col">{$t("roles.edit.rulescols.portrange")}</th>
<th scope="col">{$t("roles.edit.rulescols.allowedrole")}</th>
<th scope="col">{$t("roles.edit.rulescols.actions")}</th>
</tr>
</thead>
<tbody>
{#each rules as rule}
<tr>
<td>{rule.description}</td>
<td>{protoToStringName(rule.protocol)}</td>
<td>{prettyPortRange(rule.portRange)}</td>
<td>{findRole(rule.allowedRole)}</td>
<button disabled="{allowClickingOtherStuff}" on:click={() => {editRule(rule)}}>{$t("roles.edit.ruleedit")}</button>
<button disabled="{allowClickingOtherStuff}" on:click={() => {removeRule(rule)}}>{$t("roles.edit.ruleremove")}</button>
<td>
<div class="btn-group" role="group" aria-label="Actions">
<button type="button" class="btn btn-primary" disabled="{allowClickingOtherStuff}" on:click={() => {editRule(rule)}}><i class="fas fa-pencil fa-fw"></i></button>
<button type="button" class="btn btn-danger" disabled="{allowClickingOtherStuff}" on:click={() => {removeRule(rule)}}><i class="fas fa-trash fa-fw"></i></button>
</div>
</td>
</tr>
{/each}
</table>
</tbody>
<button disabled="{allowClickingOtherStuff}" on:click={() => {addRule()}}>{$t("roles.edit.rulesadd")}</button>
</table>
{#if isEditingRule}
<form on:submit|preventDefault>
<label for="ruleProtocol">{$t("roles.edit.editrule.protocol")}</label>
<select id="ruleProtocol" bind:value="{editingRuleProtocol}">
<option value="{RuleProtocol.ANY}">{$t("roles.edit.any")}</option>
<div class="container">
<div class="row">
<div class="col">
<label class="form-label" for="ruleProtocol">{$t("roles.edit.editrule.protocol")}</label>
<select class="form-select" id="ruleProtocol" bind:value="{editingRuleProtocol}">
<option selected value="{RuleProtocol.ANY}">{$t("roles.edit.any")}</option>
<option value="{RuleProtocol.TCP}">TCP</option>
<option value="{RuleProtocol.UDP}">UDP</option>
<option value="{RuleProtocol.ICMP}">ICMP</option>
</select>
<label for="rulePortRange">{$t("roles.edit.editrule.range")}</label>
<input type="text" bind:value="{editingRulePortRange}" id="rulePortRange"/>
<label for="ruleAllowedRole">{$t("roles.edit.editrule.role")}</label>
<select id="ruleAllowedRole" bind:value="{editingRuleAllowedRole}">
<option value="any">{$t("roles.edit.any")}</option>
</div>
<div class="col">
<label class="form-label" for="rulePortRange">{$t("roles.edit.editrule.range")}</label>
<input class="form-control" type="text" bind:value="{editingRulePortRange}" id="rulePortRange"/>
</div>
</div>
<div class="row">
<div class="col">
<label class="mt-2 form-label" for="ruleAllowedRole">{$t("roles.edit.editrule.role")}</label>
<select class="form-select" id="ruleAllowedRole" bind:value="{editingRuleAllowedRole}">
<option selected value="any">{$t("roles.edit.any")}</option>
{#each roles.data as role}
<option value="{role.id}">{role.name}</option>
{/each}
</select>
<label for="ruleDescription">{$t("roles.edit.editrule.desc")}</label>
<input type="text" bind:value="{editingRuleDesc}" id="ruleDescription"/>
<button on:click|preventDefault={finishEdit}>{editingExistingRule ? $t("roles.edit.editrule.edit") : $t("roles.edit.editrule.add")}</button>
<button on:click|preventDefault={cancelEdit}>{$t("roles.edit.editrule.cancel")}</button>
</div>
</div>
<div class="row">
<div class="col">
<label class="mt-2 form-label" for="ruleDescription">{$t("roles.edit.editrule.desc")}</label>
<input class="form-control" type="text" bind:value="{editingRuleDesc}" id="ruleDescription"/>
</div>
</div>
<div class="row">
<div class="col">
<button class="mt-3 mr-2 btn btn-primary" on:click|preventDefault={finishEdit}>{editingExistingRule ? $t("roles.edit.editrule.edit") : $t("roles.edit.editrule.add")}</button>
<button class="mt-3 ml-2 btn btn-outline-info" on:click|preventDefault={cancelEdit}>{$t("roles.edit.editrule.cancel")}</button>
</div>
</div>
</div>
</form>
{/if}
<br/>
<hr>
<button disabled="{allowClickingOtherStuff}">{$t("roles.edit.button")}</button>
<button disabled="{allowClickingOtherStuff}" on:click|preventDefault={() => {window.location.href = "/roles";}}>{$t("roles.edit.cancel")}</button>
<button class="btn btn-primary" disabled="{allowClickingOtherStuff}" on:click={() => {addRule()}}>{$t("roles.edit.rulesadd")} <i class="bi ms-1 fas fa-add"></i></button>
<hr>
{#if loading}
<button disabled class="btn btn-primary" on:click={roleEdit}><i class="fas fa-gear fa-spin"></i></button>
{:else}
<button class="btn btn-primary" on:click={roleEdit} disabled="{allowClickingOtherStuff}">{$t("roles.edit.button")}</button>
{/if}
<button class="btn btn-outline-info" disabled="{allowClickingOtherStuff}" on:click|preventDefault={() => {window.location.href = "/roles";}}>{$t("roles.edit.cancel")}</button>
{#if hasFormErr}
<p class="text-danger">{formErr}</p>
{/if}
</form>
</AdminLayout>
</LoadingWrapper>

View File

@ -8,18 +8,22 @@
import {PUBLIC_BASE_URL} from "$env/static/public";
import {Configuration, NetworksApi, RolesApi, FirewallRuleProtocolEnum} from "$lib/api";
import type {FirewallRule} from "$lib/api";
import AdminBar from "$components/AdminBar.svelte";
import AdminBar from "$components/AdminLayout.svelte";
import AdminLayout from "$components/AdminLayout.svelte";
let loading = true;
let isError = false;
let error = '';
$: currentlyLoading = $isLoading || loading;
$: currentlyLoading = $isLoading;
logSetup();
let logger = new Logger("roles/add/+page.svelte");
let roles;
let formErr = '';
let hasFormErr = false;
onMount(async () => {
let session_load_info = await isAuthedSession();
if (session_load_info[0] == APIResult.Failed) {
@ -267,6 +271,13 @@
}
async function roleAdd() {
hasFormErr = false;
loading = true;
if (roleName == undefined || roleName == "" || roleName == " ") {
hasFormErr = true;
formErr = $t("roles.add.error.needsname");
}
const configuration = new Configuration({
basePath: PUBLIC_BASE_URL,
accessToken: window.localStorage.getItem("session") + " " + window.localStorage.getItem("mfa")
@ -299,66 +310,108 @@
</svelte:head>
<LoadingWrapper isLoading={currentlyLoading} isError={isError} error={error}>
<AdminBar selected="roles" />
<AdminLayout selected="roles">
<h3>{$t("roles.add.title")}</h3>
<form>
<label for="roleName">{$t("roles.add.name")}</label>
<input bind:value={roleName} type="text" id="roleName" />
<label for="roleDesc">{$t("roles.add.desc")}</label>
<input bind:value={roleDescription} type="text" id="roleDesc" />
<h3>{$t("roles.add.rules")}</h3>
<label class="form-label" for="roleName">{$t("roles.add.name")}</label>
<input class="form-control" bind:value={roleName} type="text" id="roleName" />
<label class="mt-2 form-label" for="roleDesc">{$t("roles.add.desc")}</label>
<input class="form-control" bind:value={roleDescription} type="text" id="roleDesc" />
<hr>
<h5>{$t("roles.add.rules")}</h5>
<p>{$t("roles.add.rulesexplainer")}</p>
<!-- firewall rules -->
<table>
<table class="table table-dark rounded-2 table-hover">
<thead>
<tr>
<th>{$t("roles.add.rulescols.description")}</th>
<th>{$t("roles.add.rulescols.protocol")}</th>
<th>{$t("roles.add.rulescols.portrange")}</th>
<th>{$t("roles.add.rulescols.allowedrole")}</th>
<th scope="col">{$t("roles.add.rulescols.description")}</th>
<th scope="col">{$t("roles.add.rulescols.protocol")}</th>
<th scope="col">{$t("roles.add.rulescols.portrange")}</th>
<th scope="col">{$t("roles.add.rulescols.allowedrole")}</th>
<th scope="col">{$t("roles.add.rulescols.actions")}</th>
</tr>
</thead>
<tbody>
{#each rules as rule}
<tr>
<td>{rule.description}</td>
<td>{protoToStringName(rule.protocol)}</td>
<td>{prettyPortRange(rule.portRange)}</td>
<td>{findRole(rule.allowedRole)}</td>
<button disabled="{allowClickingOtherStuff}" on:click={() => {editRule(rule)}}>{$t("roles.add.ruleedit")}</button>
<button disabled="{allowClickingOtherStuff}" on:click={() => {removeRule(rule)}}>{$t("roles.add.ruleremove")}</button>
<td>
<div class="btn-group" role="group" aria-label="Actions">
<button type="button" class="btn btn-primary" disabled="{allowClickingOtherStuff}" on:click={() => {editRule(rule)}}><i class="fas fa-pencil fa-fw"></i></button>
<button type="button" class="btn btn-danger" disabled="{allowClickingOtherStuff}" on:click={() => {removeRule(rule)}}><i class="fas fa-trash fa-fw"></i></button>
</div>
</td>
</tr>
{/each}
</table>
</tbody>
<button disabled="{allowClickingOtherStuff}" on:click={() => {addRule()}}>{$t("roles.add.rulesadd")}</button>
</table>
{#if isEditingRule}
<form on:submit|preventDefault>
<label for="ruleProtocol">{$t("roles.add.editrule.protocol")}</label>
<select id="ruleProtocol" bind:value="{editingRuleProtocol}">
<option value="{RuleProtocol.ANY}">{$t("roles.add.any")}</option>
<div class="container">
<div class="row">
<div class="col">
<label class="form-label" for="ruleProtocol">{$t("roles.add.editrule.protocol")}</label>
<select class="form-select" id="ruleProtocol" bind:value="{editingRuleProtocol}">
<option selected value="{RuleProtocol.ANY}">{$t("roles.add.any")}</option>
<option value="{RuleProtocol.TCP}">TCP</option>
<option value="{RuleProtocol.UDP}">UDP</option>
<option value="{RuleProtocol.ICMP}">ICMP</option>
</select>
<label for="rulePortRange">{$t("roles.add.editrule.range")}</label>
<input type="text" bind:value="{editingRulePortRange}" id="rulePortRange"/>
<label for="ruleAllowedRole">{$t("roles.add.editrule.role")}</label>
<select id="ruleAllowedRole" bind:value="{editingRuleAllowedRole}">
<option value="any">{$t("roles.add.any")}</option>
</div>
<div class="col">
<label class="form-label" for="rulePortRange">{$t("roles.add.editrule.range")}</label>
<input class="form-control" type="text" bind:value="{editingRulePortRange}" id="rulePortRange"/>
</div>
</div>
<div class="row">
<div class="col">
<label class="mt-2 form-label" for="ruleAllowedRole">{$t("roles.add.editrule.role")}</label>
<select class="form-select" id="ruleAllowedRole" bind:value="{editingRuleAllowedRole}">
<option selected value="any">{$t("roles.add.any")}</option>
{#each roles.data as role}
<option value="{role.id}">{role.name}</option>
{/each}
</select>
<label for="ruleDescription">{$t("roles.add.editrule.desc")}</label>
<input type="text" bind:value="{editingRuleDesc}" id="ruleDescription"/>
<button on:click|preventDefault={finishEdit}>{editingExistingRule ? $t("roles.add.editrule.edit") : $t("roles.add.editrule.add")}</button>
<button on:click|preventDefault={cancelEdit}>{$t("roles.add.editrule.cancel")}</button>
</div>
</div>
<div class="row">
<div class="col">
<label class="mt-2 form-label" for="ruleDescription">{$t("roles.add.editrule.desc")}</label>
<input class="form-control" type="text" bind:value="{editingRuleDesc}" id="ruleDescription"/>
</div>
</div>
<div class="row">
<div class="col">
<button class="mt-3 mr-2 btn btn-primary" on:click|preventDefault={finishEdit}>{editingExistingRule ? $t("roles.add.editrule.edit") : $t("roles.add.editrule.add")}</button>
<button class="mt-3 ml-2 btn btn-outline-info" on:click|preventDefault={cancelEdit}>{$t("roles.add.editrule.cancel")}</button>
</div>
</div>
</div>
</form>
{/if}
<br/>
<hr>
<button on:click={roleAdd} disabled="{allowClickingOtherStuff}">{$t("roles.add.button")}</button>
<button disabled="{allowClickingOtherStuff}" on:click|preventDefault={() => {window.location.href = "/roles";}}>{$t("roles.add.cancel")}</button>
<button class="btn btn-primary" disabled="{allowClickingOtherStuff}" on:click={() => {addRule()}}>{$t("roles.add.rulesadd")} <i class="bi ms-1 fas fa-add"></i></button>
<hr>
{#if loading}
<button disabled class="btn btn-primary" on:click={roleAdd}><i class="fas fa-gear fa-spin"></i></button>
{:else}
<button class="btn btn-primary" on:click={roleAdd} disabled="{allowClickingOtherStuff}">{$t("roles.add.button")}</button>
{/if}
<button class="btn btn-outline-info" disabled="{allowClickingOtherStuff}" on:click|preventDefault={() => {window.location.href = "/roles";}}>{$t("roles.add.cancel")}</button>
{#if hasFormErr}
<p class="text-danger">{formErr}</p>
{/if}
</form>
</AdminLayout>
</LoadingWrapper>