feat: addition of Log account page
This commit is contained in:
parent
b95c12772d
commit
79e25e69bb
@ -9,6 +9,7 @@ const Account = lazy(() => import("keycloakify/account/pages/Account"));
|
|||||||
const Sessions = lazy(() => import("keycloakify/account/pages/Sessions"));
|
const Sessions = lazy(() => import("keycloakify/account/pages/Sessions"));
|
||||||
const Totp = lazy(() => import("keycloakify/account/pages/Totp"));
|
const Totp = lazy(() => import("keycloakify/account/pages/Totp"));
|
||||||
const Applications = lazy(() => import("keycloakify/account/pages/Applications"));
|
const Applications = lazy(() => import("keycloakify/account/pages/Applications"));
|
||||||
|
const Log = lazy(() => import("keycloakify/account/pages/Log"));
|
||||||
|
|
||||||
export default function Fallback(props: PageProps<KcContext, I18n>) {
|
export default function Fallback(props: PageProps<KcContext, I18n>) {
|
||||||
const { kcContext, ...rest } = props;
|
const { kcContext, ...rest } = props;
|
||||||
@ -27,6 +28,8 @@ export default function Fallback(props: PageProps<KcContext, I18n>) {
|
|||||||
return <Totp kcContext={kcContext} {...rest} />;
|
return <Totp kcContext={kcContext} {...rest} />;
|
||||||
case "applications.ftl":
|
case "applications.ftl":
|
||||||
return <Applications kcContext={kcContext} {...rest} />;
|
return <Applications kcContext={kcContext} {...rest} />;
|
||||||
|
case "log.ftl":
|
||||||
|
return <Log kcContext={kcContext} {...rest} />;
|
||||||
}
|
}
|
||||||
assert<Equals<typeof kcContext, never>>(false);
|
assert<Equals<typeof kcContext, never>>(false);
|
||||||
})()}
|
})()}
|
||||||
|
@ -3,7 +3,7 @@ import { assert } from "tsafe/assert";
|
|||||||
import type { Equals } from "tsafe";
|
import type { Equals } from "tsafe";
|
||||||
import { type ThemeType } from "keycloakify/bin/constants";
|
import { type ThemeType } from "keycloakify/bin/constants";
|
||||||
|
|
||||||
export type KcContext = KcContext.Password | KcContext.Account | KcContext.Sessions | KcContext.Totp | KcContext.Applications;
|
export type KcContext = KcContext.Password | KcContext.Account | KcContext.Sessions | KcContext.Totp | KcContext.Applications | KcContext.Log;
|
||||||
|
|
||||||
export declare namespace KcContext {
|
export declare namespace KcContext {
|
||||||
export type Common = {
|
export type Common = {
|
||||||
@ -245,6 +245,19 @@ export declare namespace KcContext {
|
|||||||
}[];
|
}[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type Log = Common & {
|
||||||
|
pageId: "log.ftl";
|
||||||
|
log: {
|
||||||
|
events: {
|
||||||
|
date: string | number | Date;
|
||||||
|
event: string;
|
||||||
|
ipAddress: string;
|
||||||
|
client: any;
|
||||||
|
details: any[];
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -186,15 +186,15 @@ export const kcContextMocks: KcContext[] = [
|
|||||||
id<KcContext.Sessions>({
|
id<KcContext.Sessions>({
|
||||||
...kcContextCommonMock,
|
...kcContextCommonMock,
|
||||||
"pageId": "sessions.ftl",
|
"pageId": "sessions.ftl",
|
||||||
sessions: {
|
"sessions": {
|
||||||
sessions: [
|
"sessions": [
|
||||||
{
|
{
|
||||||
...kcContextCommonMock.sessions,
|
...kcContextCommonMock.sessions,
|
||||||
ipAddress: "127.0.0.1",
|
"ipAddress": "127.0.0.1",
|
||||||
started: new Date().toString(),
|
"started": new Date().toString(),
|
||||||
lastAccess: new Date().toString(),
|
"lastAccess": new Date().toString(),
|
||||||
expires: new Date().toString(),
|
"expires": new Date().toString(),
|
||||||
clients: ["Chrome", "Firefox"]
|
"clients": ["Chrome", "Firefox"]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -203,26 +203,41 @@ export const kcContextMocks: KcContext[] = [
|
|||||||
id<KcContext.Totp>({
|
id<KcContext.Totp>({
|
||||||
...kcContextCommonMock,
|
...kcContextCommonMock,
|
||||||
"pageId": "totp.ftl",
|
"pageId": "totp.ftl",
|
||||||
totp: {
|
"totp": {
|
||||||
enabled: true,
|
"enabled": true,
|
||||||
totpSecretEncoded: "KVVF G2BY N4YX S6LB IUYT K2LH IFYE 4SBV",
|
"totpSecretEncoded": "KVVF G2BY N4YX S6LB IUYT K2LH IFYE 4SBV",
|
||||||
qrUrl: "#",
|
"qrUrl": "#",
|
||||||
totpSecretQrCode:
|
"totpSecretQrCode":
|
||||||
"iVBORw0KGgoAAAANSUhEUgAAAPYAAAD2AQAAAADNaUdlAAACM0lEQVR4Xu3OIZJgOQwDUDFd2UxiurLAVnnbHw4YGDKtSiWOn4Gxf81//7r/+q8b4HfLGBZDK9d85NmNR+sB42sXvOYrN5P1DcgYYFTGfOlbzE8gzwy3euweGizw7cfdl34/GRhlkxjKNV+5AebPXPORX1JuB9x8ZfbyyD2y1krWAKsbMq1HnqQDaLfa77p4+MqvzEGSqvSAD/2IHW2yHaigR9tX3m8dDIYGcNf3f+gDpVBZbZU77zyJ6Rlcy+qoTMG887KAPD9hsh6a1Sv3gJUHGHUAxSMzj7zqDDe7Phmt2eG+8UsMxjRGm816MAO+8VMl1R1jGHOrZB/5Zo/WXAPgxixm9Mo96vDGrM1eOto8c4Ax4wF437mifOXlpiPzCnN7Y9l95NnEMxgMY9AAGA8fucH14Y1aVb6N/cqrmyh0BVht7k1e+bU8LK0Cg5vmVq9c5vHIjOfqxDIfeTraNVTwewa4wVe+SW5N+uP1qACeudUZbqGOfA6VZV750Noq2Xx3kpveV44ZelSV1V7KFHzkWyVrrlUwG0Pl9pWnoy3vsQoME6vKI69i5osVgwWzHT7zjmJtMcNUSVn1oYMd7ZodbgowZl45VG0uVuLPUr1yc79uaQBag/mqR34xhlWyHm1prplHboCWdZ4TeZjsK8+dI+jbz1C5hl65mcpgB5dhcj8+dGO+0Ko68+lD37JDD83dpDLzzK+TrQyaVwGj6pUboGV+7+AyN8An/pf84/7rv/4/1l4OCc/1BYMAAAAASUVORK5CYII=",
|
"iVBORw0KGgoAAAANSUhEUgAAAPYAAAD2AQAAAADNaUdlAAACM0lEQVR4Xu3OIZJgOQwDUDFd2UxiurLAVnnbHw4YGDKtSiWOn4Gxf81//7r/+q8b4HfLGBZDK9d85NmNR+sB42sXvOYrN5P1DcgYYFTGfOlbzE8gzwy3euweGizw7cfdl34/GRhlkxjKNV+5AebPXPORX1JuB9x8ZfbyyD2y1krWAKsbMq1HnqQDaLfa77p4+MqvzEGSqvSAD/2IHW2yHaigR9tX3m8dDIYGcNf3f+gDpVBZbZU77zyJ6Rlcy+qoTMG887KAPD9hsh6a1Sv3gJUHGHUAxSMzj7zqDDe7Phmt2eG+8UsMxjRGm816MAO+8VMl1R1jGHOrZB/5Zo/WXAPgxixm9Mo96vDGrM1eOto8c4Ax4wF437mifOXlpiPzCnN7Y9l95NnEMxgMY9AAGA8fucH14Y1aVb6N/cqrmyh0BVht7k1e+bU8LK0Cg5vmVq9c5vHIjOfqxDIfeTraNVTwewa4wVe+SW5N+uP1qACeudUZbqGOfA6VZV750Noq2Xx3kpveV44ZelSV1V7KFHzkWyVrrlUwG0Pl9pWnoy3vsQoME6vKI69i5osVgwWzHT7zjmJtMcNUSVn1oYMd7ZodbgowZl45VG0uVuLPUr1yc79uaQBag/mqR34xhlWyHm1prplHboCWdZ4TeZjsK8+dI+jbz1C5hl65mcpgB5dhcj8+dGO+0Ko68+lD37JDD83dpDLzzK+TrQyaVwGj6pUboGV+7+AyN8An/pf84/7rv/4/1l4OCc/1BYMAAAAASUVORK5CYII=",
|
||||||
manualUrl: "#",
|
"manualUrl": "#",
|
||||||
totpSecret: "G4nsI8lQagRMUchH8jEG",
|
"totpSecret": "G4nsI8lQagRMUchH8jEG",
|
||||||
otpCredentials: [],
|
"otpCredentials": [],
|
||||||
supportedApplications: ["totpAppFreeOTPName", "totpAppMicrosoftAuthenticatorName", "totpAppGoogleName"],
|
"supportedApplications": ["totpAppFreeOTPName", "totpAppMicrosoftAuthenticatorName", "totpAppGoogleName"],
|
||||||
policy: {
|
"policy": {
|
||||||
algorithm: "HmacSHA1",
|
"algorithm": "HmacSHA1",
|
||||||
digits: 6,
|
"digits": 6,
|
||||||
lookAheadWindow: 1,
|
"lookAheadWindow": 1,
|
||||||
type: "totp",
|
"type": "totp",
|
||||||
period: 30
|
"period": 30
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mode: "qr",
|
"mode": "qr",
|
||||||
isAppInitiatedAction: false,
|
"isAppInitiatedAction": false,
|
||||||
"stateChecker": ""
|
"stateChecker": ""
|
||||||
|
}),
|
||||||
|
id<KcContext.Log>({
|
||||||
|
...kcContextCommonMock,
|
||||||
|
"pageId": "log.ftl",
|
||||||
|
"log": {
|
||||||
|
"events": [
|
||||||
|
{
|
||||||
|
"date": "2/21/2024, 1:28:39 PM",
|
||||||
|
"event": "login",
|
||||||
|
"ipAddress": "172.17.0.1",
|
||||||
|
"client": "security-admin-console",
|
||||||
|
"details": ["auth_method = openid-connect, username = admin"]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
70
src/account/pages/Log.tsx
Normal file
70
src/account/pages/Log.tsx
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import type { PageProps } from "keycloakify/account/pages/PageProps";
|
||||||
|
import type { KcContext } from "../kcContext";
|
||||||
|
import type { I18n } from "../i18n";
|
||||||
|
import { Key } from "react";
|
||||||
|
import { useGetClassName } from "../lib/useGetClassName";
|
||||||
|
|
||||||
|
export default function Log(props: PageProps<Extract<KcContext, { pageId: "log.ftl" }>, I18n>) {
|
||||||
|
const { kcContext, i18n, doUseDefaultCss, classes, Template } = props;
|
||||||
|
|
||||||
|
const { getClassName } = useGetClassName({
|
||||||
|
doUseDefaultCss,
|
||||||
|
classes
|
||||||
|
});
|
||||||
|
|
||||||
|
const { log } = kcContext;
|
||||||
|
|
||||||
|
const { msg } = i18n;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Template {...{ kcContext, i18n, doUseDefaultCss, classes }} active="log">
|
||||||
|
<div className={getClassName("kcContentWrapperClass")}>
|
||||||
|
<div className="col-md-10">
|
||||||
|
<h2>{msg("accountLogHtmlTitle")}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table className="table table-striped table-bordered">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<td>{msg("date")}</td>
|
||||||
|
<td>{msg("event")}</td>
|
||||||
|
<td>{msg("ip")}</td>
|
||||||
|
<td>{msg("client")}</td>
|
||||||
|
<td>{msg("details")}</td>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
{log.events.map(
|
||||||
|
(
|
||||||
|
event: {
|
||||||
|
date: string | number | Date;
|
||||||
|
event: string;
|
||||||
|
ipAddress: string;
|
||||||
|
client: any;
|
||||||
|
details: any[];
|
||||||
|
},
|
||||||
|
index: Key | null | undefined
|
||||||
|
) => (
|
||||||
|
<tr key={index}>
|
||||||
|
<td>{event.date ? new Date(event.date).toLocaleString() : ""}</td>
|
||||||
|
<td>{event.event}</td>
|
||||||
|
<td>{event.ipAddress}</td>
|
||||||
|
<td>{event.client || ""}</td>
|
||||||
|
<td>
|
||||||
|
{event.details.map((detail, detailIndex) => (
|
||||||
|
<span key={detailIndex}>
|
||||||
|
{`${detail.key} = ${detail.value}`}
|
||||||
|
{detailIndex < event.details.length - 1 && ", "}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</Template>
|
||||||
|
);
|
||||||
|
}
|
@ -27,7 +27,7 @@ export const loginThemePageIds = [
|
|||||||
"saml-post-form.ftl"
|
"saml-post-form.ftl"
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export const accountThemePageIds = ["password.ftl", "account.ftl", "sessions.ftl", "totp.ftl", "applications.ftl"] as const;
|
export const accountThemePageIds = ["password.ftl", "account.ftl", "sessions.ftl", "totp.ftl", "applications.ftl", "log.ftl"] as const;
|
||||||
|
|
||||||
export type LoginThemePageId = (typeof loginThemePageIds)[number];
|
export type LoginThemePageId = (typeof loginThemePageIds)[number];
|
||||||
export type AccountThemePageId = (typeof accountThemePageIds)[number];
|
export type AccountThemePageId = (typeof accountThemePageIds)[number];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user