mirror of
https://github.com/1f349/admin.1f349.com.git
synced 2024-11-12 14:41:34 +00:00
Add certificate view
This commit is contained in:
parent
8ecd8c287a
commit
0c0f2148bc
30
src/stores/certs.ts
Normal file
30
src/stores/certs.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import {writable} from "svelte/store";
|
||||
|
||||
export interface Cert {
|
||||
id: number;
|
||||
auto_renew: boolean;
|
||||
active: boolean;
|
||||
renewing: boolean;
|
||||
renew_failed: boolean;
|
||||
not_after: string;
|
||||
updated_at: string;
|
||||
domains: string[];
|
||||
}
|
||||
|
||||
export function siteEqual(a: Cert | null, b: Cert | null) {
|
||||
if (a == null || b == null) return false;
|
||||
a.domains.sort();
|
||||
b.domains.sort();
|
||||
return (
|
||||
a.id == b.id &&
|
||||
a.auto_renew == b.auto_renew &&
|
||||
a.active == b.active &&
|
||||
a.renewing == b.renewing &&
|
||||
a.renew_failed == b.renew_failed &&
|
||||
a.not_after == b.not_after &&
|
||||
a.updated_at == b.updated_at &&
|
||||
JSON.stringify(a.domains) == JSON.stringify(b.domains)
|
||||
);
|
||||
}
|
||||
|
||||
export const certsTable = writable<{[key: string]: Cert}>({});
|
@ -1 +1,122 @@
|
||||
<div style="padding:8px;background-color:#bb7900;">Warning: This is currently still under development</div>
|
||||
<script lang="ts">
|
||||
import {domainOption} from "../stores/domain-option";
|
||||
import {getBearer} from "../stores/login";
|
||||
import {type Cert, certsTable} from "../stores/certs";
|
||||
|
||||
const apiOrchid = import.meta.env.VITE_API_ORCHID;
|
||||
|
||||
let tableKeys: string[] = [];
|
||||
$: tableKeys = Object.entries($certsTable)
|
||||
.map(x => x[1])
|
||||
.filter(x => x.domains.map(x => domainFilter(x, $domainOption)).reduce((a, b) => a || b))
|
||||
.sort((a, b) => {
|
||||
// sort renew failed first
|
||||
if (a.renew_failed && b.renew_failed) return a.id - b.id;
|
||||
if (a.renew_failed) return -1;
|
||||
if (b.renew_failed) return 1;
|
||||
return a.id - b.id;
|
||||
})
|
||||
.map(x => x.id.toString());
|
||||
|
||||
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 promiseForTable: Promise<void> = Object.entries($certsTable).length === 0 ? reloadTable() : Promise.resolve();
|
||||
|
||||
function reloadTable(): Promise<void> {
|
||||
return new Promise<void>((res, rej) => {
|
||||
fetch(apiOrchid + "/owned", {headers: {Authorization: getBearer()}})
|
||||
.then(x => {
|
||||
if (x.status !== 200) throw new Error("Unexpected status code: " + x.status);
|
||||
return x.json();
|
||||
})
|
||||
.then(x => {
|
||||
let rows = x as Map<number, Cert>;
|
||||
Object.values(rows).forEach(x => {
|
||||
$certsTable[Object(x.id).toString()] = x;
|
||||
});
|
||||
console.log($certsTable);
|
||||
res();
|
||||
})
|
||||
.catch(x => rej(x));
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="wrapper">
|
||||
<div style="padding:8px;background-color:#bb7900;">Warning: This is currently still under development</div>
|
||||
|
||||
<div class="scrolling-area">
|
||||
{#await promiseForTable}
|
||||
<div class="text-padding">
|
||||
<div>Loading...</div>
|
||||
</div>
|
||||
{:then}
|
||||
<table class="main-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Auto Renew</th>
|
||||
<th>Active</th>
|
||||
<th>Renewing</th>
|
||||
<th>Renew Failed</th>
|
||||
<th>Not After</th>
|
||||
<th>Domains</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="invert-rows">
|
||||
{#each tableKeys as key (key)}
|
||||
{@const cert = $certsTable[key]}
|
||||
<tr class:cert-error={cert.renew_failed}>
|
||||
<td>{cert.id}</td>
|
||||
<td>{cert.auto_renew}</td>
|
||||
<td>{cert.active}</td>
|
||||
<td>{cert.renewing}</td>
|
||||
<td>{cert.renew_failed}</td>
|
||||
<td>
|
||||
<div>{cert.not_after}</div>
|
||||
<div>{Math.round((new Date(cert.not_after).getTime() - new Date().getTime()) / (1000 * 60 * 60 * 24))} days until expiry</div>
|
||||
</td>
|
||||
<td class="branch-cell">
|
||||
{#each cert.domains as domain}
|
||||
<div>{domain}</div>
|
||||
{/each}
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
</tbody>
|
||||
</table>
|
||||
{:catch err}
|
||||
<div class="text-padding">
|
||||
<div>Administrator... I hardly know her?</div>
|
||||
<div>{err}</div>
|
||||
</div>
|
||||
{/await}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.branch-cell {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(1, auto);
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
// css please explain yourself
|
||||
tr.cert-error.cert-error {
|
||||
&:nth-child(2n + 1) {
|
||||
background-color: #510000;
|
||||
}
|
||||
|
||||
&:nth-child(2n) {
|
||||
background-color: #330000;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -150,6 +150,56 @@ func apiServer(verify mjwt.Verifier) {
|
||||
}
|
||||
json.NewEncoder(rw).Encode(m)
|
||||
}))
|
||||
r.Handle("/v1/orchid/owned", hasPerm(verify, "orchid:cert", func(rw http.ResponseWriter, req *http.Request) {
|
||||
m := make(map[int]any, 41)
|
||||
for i := 0; i < 20; i++ {
|
||||
u := uuid.NewString()
|
||||
m[i] = map[string]any{
|
||||
"id": i + 1,
|
||||
"auto_renew": true,
|
||||
"active": true,
|
||||
"renewing": false,
|
||||
"renew_failed": false,
|
||||
"not_after": "2024-02-06T11:52:05Z",
|
||||
"updated_at": "2023-11-08T07:32:08Z",
|
||||
"domains": []string{
|
||||
u + ".example.com",
|
||||
"*." + u + ".example.com",
|
||||
},
|
||||
}
|
||||
}
|
||||
for i := 0; i < 20; i++ {
|
||||
u := uuid.NewString()
|
||||
m[i+20] = map[string]any{
|
||||
"id": i + 21,
|
||||
"auto_renew": false,
|
||||
"active": false,
|
||||
"renewing": false,
|
||||
"renew_failed": false,
|
||||
"not_after": "2024-02-06T11:52:05Z",
|
||||
"updated_at": "2023-11-08T07:32:08Z",
|
||||
"domains": []string{
|
||||
u + ".example.org",
|
||||
"*." + u + ".example.org",
|
||||
},
|
||||
}
|
||||
}
|
||||
u := uuid.NewString()
|
||||
m[40] = map[string]any{
|
||||
"id": 41,
|
||||
"auto_renew": false,
|
||||
"active": false,
|
||||
"renewing": false,
|
||||
"renew_failed": true,
|
||||
"not_after": "2024-02-06T11:52:05Z",
|
||||
"updated_at": "2023-11-08T07:32:08Z",
|
||||
"domains": []string{
|
||||
u + ".example.org",
|
||||
"*." + u + ".example.org",
|
||||
},
|
||||
}
|
||||
json.NewEncoder(rw).Encode(m)
|
||||
}))
|
||||
r.Handle("/v1/sites", hasPerm(verify, "sites:manage", func(rw http.ResponseWriter, req *http.Request) {
|
||||
if req.Method == http.MethodPost {
|
||||
defer req.Body.Close()
|
||||
|
Loading…
Reference in New Issue
Block a user