Skip to content

Commit

Permalink
Merge pull request #210 from sebadob/ui-events-section
Browse files Browse the repository at this point in the history
UI: Events section to fetch and view historic events from the database
  • Loading branch information
sebadob authored Dec 20, 2023
2 parents 3622c0a + a2e0a37 commit ece73bb
Show file tree
Hide file tree
Showing 15 changed files with 263 additions and 41 deletions.
17 changes: 16 additions & 1 deletion frontend/src/components/admin/AdminMain.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import Blacklist from "./blacklist/Blacklist.svelte";
import IconKey from "$lib/icons/IconKey.svelte";
import ApiKeys from "./api_keys/ApiKeys.svelte";
import EventsArchive from "./events/EventsArchive.svelte";
import IconBellAlert from "$lib/icons/IconBellAlert.svelte";
export let sessionInfo = {};
export let selected = 'Users';
Expand Down Expand Up @@ -82,6 +84,11 @@
title = 'Sessions';
break;
}
case 'Events': {
window.history.pushState('Sessions', '', '/auth/v1/admin/events');
title = 'Events';
break;
}
case 'Blacklist': {
window.history.pushState('Blacklist', '', '/auth/v1/admin/blacklist');
title = 'Blacklist';
Expand Down Expand Up @@ -173,8 +180,12 @@
<IconShieldCheck/>
</NavEntry>

<NavEntry label="Events">
<IconBellAlert/>
</NavEntry>

<NavEntry label="Blacklist">
<IconStop width=24 />
<IconStop width={24} />
</NavEntry>

<NavEntry label="ApiKeys">
Expand Down Expand Up @@ -224,6 +235,10 @@
<ContentWrapper bind:eventsWide bind:eventsCollapsed>
<Sessions/>
</ContentWrapper>
{:else if 'Events' === selected}
<ContentWrapper bind:eventsWide bind:eventsCollapsed>
<EventsArchive/>
</ContentWrapper>
{:else if 'Blacklist' === selected}
<ContentWrapper bind:eventsWide bind:eventsCollapsed>
<Blacklist/>
Expand Down
6 changes: 2 additions & 4 deletions frontend/src/components/admin/events/Event.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
<script>
import {formatDateFromTs} from "../../../utils/helpers.js";
import {formatDateFromTs, eventColor} from "../../../utils/helpers.js";
import {onMount} from "svelte";
export let event;
export let eventColor = () => {
};
export let collapsed = true;
export let wide;
Expand Down Expand Up @@ -174,7 +172,7 @@
}
.col-typ {
width: 9rem;
width: 9.5rem;
}
.col-ip {
Expand Down
21 changes: 4 additions & 17 deletions frontend/src/components/admin/events/Events.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -57,20 +57,7 @@
eventLevel = await readSavedEventLevel();
});
function eventColor(level) {
switch (level) {
case 'test':
return '#b2b2b2';
case 'info':
return '#388c51';
case 'notice':
return '#3d5d99';
case 'warning':
return '#c29a4f';
case 'critical':
return '#993d49';
}
}
//
async function readSavedEventLevel() {
return localStorage.getItem('eventLevel') || 'Info';
Expand Down Expand Up @@ -134,7 +121,7 @@
<Button
on:click={sendTestEvent}
level=3
level={3}
>
TEST
</Button>
Expand All @@ -151,13 +138,13 @@
<div class={widthWide ? 'dataWide' : widthCollapsed ? 'dataCollapsed' : 'data'}>
{#each eventsFiltered as event (event.id)}
<Event bind:event eventColor={eventColor} collapsed={collapsed && !isHover} bind:wide/>
<Event bind:event collapsed={collapsed && !isHover} bind:wide/>
{/each}
</div>
</div>
{#if !collapsed || isHover}
<EventsLegend eventColor={eventColor} bind:wide/>
<EventsLegend bind:wide/>
{/if}
</div>
Expand Down
150 changes: 150 additions & 0 deletions frontend/src/components/admin/events/EventsArchive.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
<script>
import {onMount} from "svelte";
import {postEvents} from "../../../utils/dataFetchingAdmin.js";
import {formatDateToDateInput, formatUtcTsFromDateInput} from "../../../utils/helpers.js";
import OrderSearchBar from "$lib/search/OrderSearchBar.svelte";
import Input from "$lib/inputs/Input.svelte";
import {EVENT_LEVELS, EVENT_TYPES} from "../../../utils/constants.js";
import OptionSelect from "$lib/OptionSelect.svelte";
import Event from "./Event.svelte";
import Switch from "$lib/Switch.svelte";
let err = '';
let events = [];
let resEvents = [];
let from = formatDateToDateInput(new Date(new Date().getTime() - 3600 * 1000));
/** @type {string | undefined} */
let until = undefined;
let level = 'Info';
let filter = false;
let typ = EVENT_TYPES[0];
$: if (from || until || level || filter || typ) {
fetchData();
}
let searchOptions = [
{
label: 'IP',
callback: (item, search) => item.ip?.includes(search),
},
// {
// label: 'Content',
// callback: (item, search) => item.data?.includes(search)
// || item.text?.toLowerCase()?.contains(search.toLowerCase()),
// },
{
label: 'Content',
callback: (item, search) => item.text?.toLowerCase()?.includes(search.toLowerCase()),
},
];
let orderOptions = [
{label: 'Timestamp', callback: (a, b) => a.timestamp - b.timestamp},
{label: 'Level', callback: (a, b) => a.level.localeCompare(b.level)},
{label: 'Type', callback: (a, b) => a.typ.localeCompare(b.typ)},
];
onMount(() => {
fetchData();
});
async function fetchData() {
let data = {
from: formatUtcTsFromDateInput(from),
level: level.toLowerCase(),
};
if (until) {
data.until = formatUtcTsFromDateInput(until);
}
if (filter) {
data.typ = typ;
}
let res = await postEvents(data);
let body = await res.json();
if (res.ok) {
events = body;
} else {
err = body.message;
}
}
function onSave() {
fetchData();
}
</script>
<div class="content">
<div class="row">
<OrderSearchBar
items={events}
bind:resItems={resEvents}
searchOptions={searchOptions}
orderOptions={orderOptions}
firstDirReverse
/>
</div>
<div class="row filter">
<Input
type="datetime-local"
step="60"
width="17.5rem"
bind:value={from}
max="2099-01-01T00:00"
>
FROM
</Input>
<Input
type="datetime-local"
step="60"
width="17rem"
bind:value={until}
max="2099-01-01T00:00"
>
UNTIL
</Input>
</div>
<div class="row filterOpts">
<div style:margin="0 5.5rem 0 .25rem">
<OptionSelect
bind:value={level}
options={EVENT_LEVELS}
/>
</div>
Filter
<Switch bind:selected={filter} />
{#if filter}
<OptionSelect
bind:value={typ}
options={EVENT_TYPES}
/>
{/if}
</div>
{#if resEvents.length === 0}
<div class="row">
No events found
</div>
{:else}
{#each resEvents as event (event.id)}
<Event bind:event collapsed={false} wide />
{/each}
{/if}
</div>
<style>
.filter, .filterOpts {
margin: -.5rem 0 1rem -.5rem;
}
.filterOpts {
gap: 1rem;
}
.row {
display: flex;
flex-wrap: wrap;
align-items: center;
}
</style>
4 changes: 2 additions & 2 deletions frontend/src/components/admin/events/EventsLegend.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script>
export let eventColor = () => {
};
import {eventColor} from "../../../utils/helpers.js";
export let wide;
</script>

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/admin/sessions/Sessions.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
let searchOptions = [
{
label: ' User ID',
label: 'User ID',
callback: (item, search) => item.user_id?.toLowerCase().includes(search.toLowerCase()),
},
{
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/admin/users/UserInfo.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,10 @@
<Input
type="datetime-local"
step="60"
width="18rem"
width="16rem"
bind:value={userExpires}
on:input={validateForm}
min={new Date().toISOString().split('.')[0]}
min={formatDateToDateInput(new Date())}
max="2099-01-01T00:00"
>
USER EXPIRES
Expand Down
20 changes: 20 additions & 0 deletions frontend/src/lib/icons/IconBellAlert.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script>
export let opacity = 0.9;
export let width = 24;
</script>

<svg
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width={2}
width={width}
opacity={opacity}
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M14.857 17.082a23.848 23.848 0 0 0 5.454-1.31A8.967 8.967 0 0 1 18 9.75V9A6 6 0 0 0 6 9v.75a8.967 8.967 0 0 1-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 0 1-5.714 0m5.714 0a3 3 0 1 1-5.714 0M3.124 7.5A8.969 8.969 0 0 1 5.292 3m13.416 0a8.969 8.969 0 0 1 2.168 4.5"
/>
</svg>

5 changes: 5 additions & 0 deletions frontend/src/routes/admin/events/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script>
import AdminMainPre from "../../../components/admin/AdminMainPre.svelte";
</script>

<AdminMainPre selected="Events"/>
17 changes: 17 additions & 0 deletions frontend/src/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,23 @@ export const EVENT_LEVELS = [
'Warning',
'Critical'
]
export const EVENT_TYPES = [
'InvalidLogins',
'IpBlacklisted',
'IpBlacklistRemoved',
'JwksRotated',
'NewUserRegistered',
'NewRauthyAdmin',
'NewRauthyVersion',
'PossibleBruteForce',
'RauthyStarted',
'RauthyHealthy',
'RauthyUnhealthy',
'SecretsMigrated',
'UserEmailChange',
'UserPasswordReset',
'Test',
]
export const LANGUAGES = ['DE', 'EN'];
export const TOKEN_ALGS = [
'RS256',
Expand Down
9 changes: 9 additions & 0 deletions frontend/src/utils/dataFetchingAdmin.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,15 @@ export async function postEncMigrate(data) {
return await checkRedirectForbidden(res);
}

export async function postEvents(data) {
const res = await fetch('/auth/v1/events', {
method: 'POST',
headers: getHeaders(),
body: JSON.stringify(data),
});
return await checkRedirectForbidden(res);
}

export async function getGroups() {
const res = await fetch('/auth/v1/groups', {
method: 'GET',
Expand Down
18 changes: 17 additions & 1 deletion frontend/src/utils/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,25 @@ export const computePow = (powChallenge) => {
};
}

export function eventColor(level) {
switch (level) {
case 'test':
return '#b2b2b2';
case 'info':
return '#388c51';
case 'notice':
return '#3d5d99';
case 'warning':
return '#c29a4f';
case 'critical':
return '#993d49';
}
}


export const formatDateToDateInput = date => {
return date.toISOString().split('.')[0];
return date.toISOString().slice(0, 16);
// return date.toISOString().split('.')[0];
}

export const formatUtcTsFromDateInput = inputDate => {
Expand Down
Loading

0 comments on commit ece73bb

Please sign in to comment.