mirror of
https://github.com/1f349/admin.1f349.com.git
synced 2024-11-09 22:32:57 +00:00
Add global domain option and fix some minor bugs
This commit is contained in:
parent
899cf20408
commit
1315a8912b
@ -3,8 +3,9 @@
|
|||||||
import GeneralView from "./views/GeneralView.svelte";
|
import GeneralView from "./views/GeneralView.svelte";
|
||||||
import VioletView from "./views/VioletView.svelte";
|
import VioletView from "./views/VioletView.svelte";
|
||||||
import OrchidView from "./views/OrchidView.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 {openLoginPopup} from "./utils/login-popup";
|
||||||
|
import {domainOption} from "./stores/domain-option";
|
||||||
|
|
||||||
let sidebarOptions: Array<{name: string; view: typeof SvelteComponent<{}>}> = [
|
let sidebarOptions: Array<{name: string; view: typeof SvelteComponent<{}>}> = [
|
||||||
{name: "General", view: GeneralView},
|
{name: "General", view: GeneralView},
|
||||||
@ -15,13 +16,34 @@
|
|||||||
|
|
||||||
let tokenPerms: string[] = [];
|
let tokenPerms: string[] = [];
|
||||||
$: tokenPerms = [];
|
$: 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>
|
</script>
|
||||||
|
|
||||||
<header>
|
<header>
|
||||||
<div>
|
<div>
|
||||||
<h1>🍉 - 1f349 Admin Dashboard</h1>
|
<h1>🍉 Admin Panel</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-gap" />
|
<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">
|
<div class="nav-link">
|
||||||
<a href="https://status.1f349.net" target="_blank">Status</a>
|
<a href="https://status.1f349.net" target="_blank">Status</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -23,3 +23,9 @@
|
|||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
tr:nth-child(2n) {
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -34,20 +34,35 @@
|
|||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
tr:nth-child(2n) {
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
}
|
||||||
|
|
||||||
tr.created {
|
tr.created {
|
||||||
background-color: #1a5100;
|
background-color: #1a5100;
|
||||||
|
|
||||||
|
&:nth-child(2n) {
|
||||||
|
background-color: #103300;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.modified {
|
tr.modified {
|
||||||
background-color: #515100;
|
background-color: #515100;
|
||||||
|
|
||||||
|
&:nth-child(2n) {
|
||||||
|
background-color: #333300;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.deleted {
|
tr.deleted {
|
||||||
background-color: #510000;
|
background-color: #510000;
|
||||||
|
|
||||||
|
&:nth-child(2n) {
|
||||||
|
background-color: #330000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
td input[type="text"] {
|
td input[type="text"] {
|
||||||
font-family: "Fira Code";
|
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -23,3 +23,9 @@
|
|||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
tr:nth-child(2n) {
|
||||||
|
background-color: #2a2a2a;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
tr:nth-child(2n) {
|
tr:nth-child(2n) {
|
||||||
background-color: #293138;
|
background-color: #2a2a2a;
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.created {
|
tr.created {
|
||||||
|
3
src/stores/domain-option.ts
Normal file
3
src/stores/domain-option.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
|
export const domainOption = writable<string>("*");
|
@ -30,3 +30,18 @@ loginStore.subscribe(x => {
|
|||||||
export function getBearer() {
|
export function getBearer() {
|
||||||
return "Bearer " + (get(loginStore) as LoginStore).tokens.access;
|
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);
|
||||||
|
}
|
||||||
|
@ -3,9 +3,10 @@
|
|||||||
import RouteCreator from "../components/RouteCreator.svelte";
|
import RouteCreator from "../components/RouteCreator.svelte";
|
||||||
import RedirectRow from "../components/RedirectRow.svelte";
|
import RedirectRow from "../components/RedirectRow.svelte";
|
||||||
import RouteRow from "../components/RouteRow.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 {CSPair} from "../types/cspair";
|
||||||
import {type Route, type Redirect} from "../types/target";
|
import {type Route, type Redirect} from "../types/target";
|
||||||
|
import {domainOption} from "../stores/domain-option";
|
||||||
|
|
||||||
const apiViolet = import.meta.env.VITE_API_VIOLET;
|
const apiViolet = import.meta.env.VITE_API_VIOLET;
|
||||||
|
|
||||||
@ -18,13 +19,22 @@
|
|||||||
$: routeSrcs = Object.entries(routeData)
|
$: routeSrcs = Object.entries(routeData)
|
||||||
.filter(x => x[1].client != null || x[1].server != null)
|
.filter(x => x[1].client != null || x[1].server != null)
|
||||||
.map(x => x[0])
|
.map(x => x[0])
|
||||||
|
.filter(x => domainFilter(x, $domainOption))
|
||||||
.sort((a, b) => a.localeCompare(b));
|
.sort((a, b) => a.localeCompare(b));
|
||||||
$: redirectSrcs = Object.entries(redirectData)
|
$: redirectSrcs = Object.entries(redirectData)
|
||||||
.filter(x => x[1].client != null || x[1].server != null)
|
.filter(x => x[1].client != null || x[1].server != null)
|
||||||
.map(x => x[0])
|
.map(x => x[0])
|
||||||
|
.filter(x => domainFilter(x, $domainOption))
|
||||||
.sort((a, b) => a.localeCompare(b));
|
.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) => {
|
let promiseForRoutes = new Promise<void>((res, rej) => {
|
||||||
fetch(apiViolet + "/route", {headers: {Authorization: getBearer()}})
|
fetch(apiViolet + "/route", {headers: {Authorization: getBearer()}})
|
||||||
@ -84,8 +94,7 @@
|
|||||||
<tr><td colspan="5">Error loading row for {src}</td></tr>
|
<tr><td colspan="5">Error loading row for {src}</td></tr>
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</tbody>
|
|
||||||
<tfoot>
|
|
||||||
<RouteCreator
|
<RouteCreator
|
||||||
on:make={e => {
|
on:make={e => {
|
||||||
const x = e.detail;
|
const x = e.detail;
|
||||||
@ -94,7 +103,7 @@
|
|||||||
routeSrcs = routeSrcs;
|
routeSrcs = routeSrcs;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</tfoot>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{:catch err}
|
{:catch err}
|
||||||
<div>{err}</div>
|
<div>{err}</div>
|
||||||
@ -122,8 +131,7 @@
|
|||||||
<tr><td colspan="5">Error loading row for {src}</td></tr>
|
<tr><td colspan="5">Error loading row for {src}</td></tr>
|
||||||
{/if}
|
{/if}
|
||||||
{/each}
|
{/each}
|
||||||
</tbody>
|
|
||||||
<tfoot>
|
|
||||||
<RedirectCreator
|
<RedirectCreator
|
||||||
on:make={e => {
|
on:make={e => {
|
||||||
const x = e.detail;
|
const x = e.detail;
|
||||||
@ -132,7 +140,7 @@
|
|||||||
redirectSrcs = redirectSrcs;
|
redirectSrcs = redirectSrcs;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</tfoot>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{:catch err}
|
{:catch err}
|
||||||
<div>{err}</div>
|
<div>{err}</div>
|
||||||
|
@ -36,6 +36,8 @@ func ssoServer(signer mjwt.Signer) {
|
|||||||
ps := claims.NewPermStorage()
|
ps := claims.NewPermStorage()
|
||||||
ps.Set("violet:route")
|
ps.Set("violet:route")
|
||||||
ps.Set("violet:redirect")
|
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{
|
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,
|
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) {
|
r.Handle("/v1/violet/route", hasPerm(verify, "violet:route", func(rw http.ResponseWriter, req *http.Request) {
|
||||||
json.NewEncoder(rw).Encode([]map[string]any{
|
json.NewEncoder(rw).Encode([]map[string]any{
|
||||||
{
|
{
|
||||||
"src": "a.example.test",
|
"src": "example.com",
|
||||||
"dst": "127.0.0.1:8080",
|
"dst": "127.0.0.1:8080",
|
||||||
"flags": 181,
|
"flags": 181,
|
||||||
"active": true,
|
"active": true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "b.example.test",
|
"src": "test.example.com",
|
||||||
"dst": "127.0.0.1:8081",
|
"dst": "127.0.0.1:8081",
|
||||||
"flags": 17,
|
"flags": 17,
|
||||||
"active": true,
|
"active": true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "c.example.test",
|
"src": "example.org/hello",
|
||||||
"dst": "127.0.0.1:8082",
|
"dst": "127.0.0.1:8082",
|
||||||
"flags": 16,
|
"flags": 16,
|
||||||
"active": true,
|
"active": true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "d.example.test",
|
"src": "test.example.org/hello",
|
||||||
"dst": "127.0.0.1:8083",
|
"dst": "127.0.0.1:8083",
|
||||||
"flags": 15,
|
"flags": 15,
|
||||||
"active": true,
|
"active": true,
|
||||||
},
|
},
|
||||||
|
|
||||||
})
|
})
|
||||||
}))
|
}))
|
||||||
r.Handle("/v1/violet/redirect", hasPerm(verify, "violet:redirect", func(rw http.ResponseWriter, req *http.Request) {
|
r.Handle("/v1/violet/redirect", hasPerm(verify, "violet:redirect", func(rw http.ResponseWriter, req *http.Request) {
|
||||||
json.NewEncoder(rw).Encode([]map[string]any{
|
json.NewEncoder(rw).Encode([]map[string]any{
|
||||||
{
|
{
|
||||||
"src": "e.example.test",
|
"src": "example.org",
|
||||||
"dst": "127.0.0.1:8084",
|
"dst": "127.0.0.1:8084",
|
||||||
"flags": 181,
|
"flags": 181,
|
||||||
"active": true,
|
"active": true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "f.example.test",
|
"src": "test.example.org",
|
||||||
"dst": "127.0.0.1:8085",
|
"dst": "127.0.0.1:8085",
|
||||||
"flags": 17,
|
"flags": 17,
|
||||||
"active": true,
|
"active": true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "g.example.test",
|
"src": "example.org/hello",
|
||||||
"dst": "127.0.0.1:8086",
|
"dst": "127.0.0.1:8086",
|
||||||
"flags": 16,
|
"flags": 16,
|
||||||
"active": true,
|
"active": true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"src": "h.example.test",
|
"src": "test.example.org/hello",
|
||||||
"dst": "127.0.0.1:8087",
|
"dst": "127.0.0.1:8087",
|
||||||
"flags": 15,
|
"flags": 15,
|
||||||
"active": true,
|
"active": true,
|
||||||
|
Loading…
Reference in New Issue
Block a user