diff --git a/src/account/Fallback.tsx b/src/account/Fallback.tsx index 03e07d49..8fe62daf 100644 --- a/src/account/Fallback.tsx +++ b/src/account/Fallback.tsx @@ -9,6 +9,7 @@ const Account = lazy(() => import("keycloakify/account/pages/Account")); const Sessions = lazy(() => import("keycloakify/account/pages/Sessions")); const Totp = lazy(() => import("keycloakify/account/pages/Totp")); const Applications = lazy(() => import("keycloakify/account/pages/Applications")); +const Log = lazy(() => import("keycloakify/account/pages/Log")); export default function Fallback(props: PageProps) { const { kcContext, ...rest } = props; @@ -27,6 +28,8 @@ export default function Fallback(props: PageProps) { return ; case "applications.ftl": return ; + case "log.ftl": + return ; } assert>(false); })()} diff --git a/src/account/kcContext/KcContext.ts b/src/account/kcContext/KcContext.ts index ad6cedce..a8223737 100644 --- a/src/account/kcContext/KcContext.ts +++ b/src/account/kcContext/KcContext.ts @@ -3,7 +3,7 @@ import { assert } from "tsafe/assert"; import type { Equals } from "tsafe"; 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 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[]; + }[]; + }; + }; } { diff --git a/src/account/kcContext/kcContextMocks.ts b/src/account/kcContext/kcContextMocks.ts index 1afd18f3..dc9db34d 100644 --- a/src/account/kcContext/kcContextMocks.ts +++ b/src/account/kcContext/kcContextMocks.ts @@ -186,15 +186,15 @@ export const kcContextMocks: KcContext[] = [ id({ ...kcContextCommonMock, "pageId": "sessions.ftl", - sessions: { - sessions: [ + "sessions": { + "sessions": [ { ...kcContextCommonMock.sessions, - ipAddress: "127.0.0.1", - started: new Date().toString(), - lastAccess: new Date().toString(), - expires: new Date().toString(), - clients: ["Chrome", "Firefox"] + "ipAddress": "127.0.0.1", + "started": new Date().toString(), + "lastAccess": new Date().toString(), + "expires": new Date().toString(), + "clients": ["Chrome", "Firefox"] } ] }, @@ -203,26 +203,41 @@ export const kcContextMocks: KcContext[] = [ id({ ...kcContextCommonMock, "pageId": "totp.ftl", - totp: { - enabled: true, - totpSecretEncoded: "KVVF G2BY N4YX S6LB IUYT K2LH IFYE 4SBV", - qrUrl: "#", - totpSecretQrCode: + "totp": { + "enabled": true, + "totpSecretEncoded": "KVVF G2BY N4YX S6LB IUYT K2LH IFYE 4SBV", + "qrUrl": "#", + "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=", - manualUrl: "#", - totpSecret: "G4nsI8lQagRMUchH8jEG", - otpCredentials: [], - supportedApplications: ["totpAppFreeOTPName", "totpAppMicrosoftAuthenticatorName", "totpAppGoogleName"], - policy: { - algorithm: "HmacSHA1", - digits: 6, - lookAheadWindow: 1, - type: "totp", - period: 30 + "manualUrl": "#", + "totpSecret": "G4nsI8lQagRMUchH8jEG", + "otpCredentials": [], + "supportedApplications": ["totpAppFreeOTPName", "totpAppMicrosoftAuthenticatorName", "totpAppGoogleName"], + "policy": { + "algorithm": "HmacSHA1", + "digits": 6, + "lookAheadWindow": 1, + "type": "totp", + "period": 30 } }, - mode: "qr", - isAppInitiatedAction: false, + "mode": "qr", + "isAppInitiatedAction": false, "stateChecker": "" + }), + id({ + ...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"] + } + ] + } }) ]; diff --git a/src/account/pages/Log.tsx b/src/account/pages/Log.tsx new file mode 100644 index 00000000..392873f5 --- /dev/null +++ b/src/account/pages/Log.tsx @@ -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, I18n>) { + const { kcContext, i18n, doUseDefaultCss, classes, Template } = props; + + const { getClassName } = useGetClassName({ + doUseDefaultCss, + classes + }); + + const { log } = kcContext; + + const { msg } = i18n; + + return ( + + ); +} diff --git a/src/bin/keycloakify/generateFtl/pageId.ts b/src/bin/keycloakify/generateFtl/pageId.ts index 3188198f..e0dce92c 100644 --- a/src/bin/keycloakify/generateFtl/pageId.ts +++ b/src/bin/keycloakify/generateFtl/pageId.ts @@ -27,7 +27,7 @@ export const loginThemePageIds = [ "saml-post-form.ftl" ] 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 AccountThemePageId = (typeof accountThemePageIds)[number];