Add global domain option and fix some minor bugs

This commit is contained in:
Melon 2023-10-28 12:43:34 +01:00
parent 899cf20408
commit 1315a8912b
Signed by: melon
GPG Key ID: 6C9D970C50D26A25
9 changed files with 97 additions and 21 deletions

View File

@ -3,8 +3,9 @@
import GeneralView from "./views/GeneralView.svelte";
import VioletView from "./views/VioletView.svelte";
import OrchidView from "./views/OrchidView.svelte";
import {loginStore} from "./stores/login";
import {loginStore, parseJwt, type LoginStore} from "./stores/login";
import {openLoginPopup} from "./utils/login-popup";
import {domainOption} from "./stores/domain-option";
let sidebarOptions: Array<{name: string; view: typeof SvelteComponent<{}>}> = [
{name: "General", view: GeneralView},
@ -15,13 +16,34 @@
let tokenPerms: string[] = [];
$: tokenPerms = [];
let domainOptions: string[];
$: domainOptions = getDomainOptions($loginStore);
function getDomainOptions(login: LoginStore | null) {
let accessToken = login?.tokens?.access;
if (accessToken == null) return [];
let jwt = parseJwt(accessToken);
return jwt.per.filter((x: string) => x.startsWith("domain:owns=")).map((x: string) => x.slice("domain:owns=".length));
}
</script>
<header>
<div>
<h1>🍉 - 1f349 Admin Dashboard</h1>
<h1>🍉 Admin Panel</h1>
</div>
<div class="flex-gap" />
<div>
<label>
<span>Domain:</span>
<select bind:value={$domainOption}>
<option value="*">All</option>
{#each domainOptions as domain}
<option value={domain}>{domain}</option>
{/each}
</select>
</label>
</div>
<div class="nav-link">
<a href="https://status.1f349.net" target="_blank">Status</a>
</div>

View File

@ -23,3 +23,9 @@
</button>
</td>
</tr>
<style lang="scss">
tr:nth-child(2n) {
background-color: #2a2a2a;
}
</style>

View File

@ -34,20 +34,35 @@
{/if}
<style lang="scss">
tr:nth-child(2n) {
background-color: #2a2a2a;
}
tr.created {
background-color: #1a5100;
&:nth-child(2n) {
background-color: #103300;
}
}
tr.modified {
background-color: #515100;
&:nth-child(2n) {
background-color: #333300;
}
}
tr.deleted {
background-color: #510000;
&:nth-child(2n) {
background-color: #330000;
}
}
td input[type="text"] {
font-family: "Fira Code";
padding: 4px;
}
</style>

View File

@ -23,3 +23,9 @@
</button>
</td>
</tr>
<style lang="scss">
tr:nth-child(2n) {
background-color: #2a2a2a;
}
</style>

View File

@ -35,7 +35,7 @@
<style lang="scss">
tr:nth-child(2n) {
background-color: #293138;
background-color: #2a2a2a;
}
tr.created {

View File

@ -0,0 +1,3 @@
import { writable } from "svelte/store";
export const domainOption = writable<string>("*");

View File

@ -30,3 +30,18 @@ loginStore.subscribe(x => {
export function getBearer() {
return "Bearer " + (get(loginStore) as LoginStore).tokens.access;
}
export function parseJwt(token: string) {
const base64Url = token.split(".")[1];
const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
const jsonPayload = decodeURIComponent(
window
.atob(base64)
.split("")
.map(function (c) {
return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
})
.join(""),
);
return JSON.parse(jsonPayload);
}

View File

@ -3,9 +3,10 @@
import RouteCreator from "../components/RouteCreator.svelte";
import RedirectRow from "../components/RedirectRow.svelte";
import RouteRow from "../components/RouteRow.svelte";
import {getBearer} from "../stores/login";
import {getBearer, loginStore, parseJwt, type LoginStore} from "../stores/login";
import type {CSPair} from "../types/cspair";
import {type Route, type Redirect} from "../types/target";
import {domainOption} from "../stores/domain-option";
const apiViolet = import.meta.env.VITE_API_VIOLET;
@ -18,13 +19,22 @@
$: routeSrcs = Object.entries(routeData)
.filter(x => x[1].client != null || x[1].server != null)
.map(x => x[0])
.filter(x => domainFilter(x, $domainOption))
.sort((a, b) => a.localeCompare(b));
$: redirectSrcs = Object.entries(redirectData)
.filter(x => x[1].client != null || x[1].server != null)
.map(x => x[0])
.filter(x => domainFilter(x, $domainOption))
.sort((a, b) => a.localeCompare(b));
$: console.log(routeData);
function domainFilter(src: string, domain: string) {
if (domain == "*") return true;
let n = src.indexOf("/");
if (n == -1) n = src.length;
let p = src.slice(0, n);
if (p == domain) return true;
return p.endsWith(domain);
}
let promiseForRoutes = new Promise<void>((res, rej) => {
fetch(apiViolet + "/route", {headers: {Authorization: getBearer()}})
@ -84,8 +94,7 @@
<tr><td colspan="5">Error loading row for {src}</td></tr>
{/if}
{/each}
</tbody>
<tfoot>
<RouteCreator
on:make={e => {
const x = e.detail;
@ -94,7 +103,7 @@
routeSrcs = routeSrcs;
}}
/>
</tfoot>
</tbody>
</table>
{:catch err}
<div>{err}</div>
@ -122,8 +131,7 @@
<tr><td colspan="5">Error loading row for {src}</td></tr>
{/if}
{/each}
</tbody>
<tfoot>
<RedirectCreator
on:make={e => {
const x = e.detail;
@ -132,7 +140,7 @@
redirectSrcs = redirectSrcs;
}}
/>
</tfoot>
</tbody>
</table>
{:catch err}
<div>{err}</div>

View File

@ -36,6 +36,8 @@ func ssoServer(signer mjwt.Signer) {
ps := claims.NewPermStorage()
ps.Set("violet:route")
ps.Set("violet:redirect")
ps.Set("domain:owns=example.com")
ps.Set("domain:owns=example.org")
accessToken, err := signer.GenerateJwt("81b99bd7-bf74-4cc2-9133-80ed2393dfe6", uuid.NewString(), jwt.ClaimStrings{"d0555671-df9d-42d0-a4d6-94b694251f0b"}, 15*time.Minute, auth.AccessTokenClaims{
Perms: ps,
})
@ -105,54 +107,53 @@ func apiServer(verify mjwt.Verifier) {
r.Handle("/v1/violet/route", hasPerm(verify, "violet:route", func(rw http.ResponseWriter, req *http.Request) {
json.NewEncoder(rw).Encode([]map[string]any{
{
"src": "a.example.test",
"src": "example.com",
"dst": "127.0.0.1:8080",
"flags": 181,
"active": true,
},
{
"src": "b.example.test",
"src": "test.example.com",
"dst": "127.0.0.1:8081",
"flags": 17,
"active": true,
},
{
"src": "c.example.test",
"src": "example.org/hello",
"dst": "127.0.0.1:8082",
"flags": 16,
"active": true,
},
{
"src": "d.example.test",
"src": "test.example.org/hello",
"dst": "127.0.0.1:8083",
"flags": 15,
"active": true,
},
})
}))
r.Handle("/v1/violet/redirect", hasPerm(verify, "violet:redirect", func(rw http.ResponseWriter, req *http.Request) {
json.NewEncoder(rw).Encode([]map[string]any{
{
"src": "e.example.test",
"src": "example.org",
"dst": "127.0.0.1:8084",
"flags": 181,
"active": true,
},
{
"src": "f.example.test",
"src": "test.example.org",
"dst": "127.0.0.1:8085",
"flags": 17,
"active": true,
},
{
"src": "g.example.test",
"src": "example.org/hello",
"dst": "127.0.0.1:8086",
"flags": 16,
"active": true,
},
{
"src": "h.example.test",
"src": "test.example.org/hello",
"dst": "127.0.0.1:8087",
"flags": 15,
"active": true,