Skip to content

Commit d122eba

Browse files
committed
feat:login banner
Display a login banner via WELCOME_MESSAGE env variable in the backend
1 parent 0dfebe2 commit d122eba

10 files changed

Lines changed: 90 additions & 4 deletions

File tree

backend/app/api/v1/auth/auth.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
login_service,
1010
logout_service,
1111
)
12+
from app.core.config import settings
1213
from app.core.mfa import (
1314
setup_mfa_service,
1415
validate_mfa_and_issue_token_service,
@@ -90,3 +91,11 @@ def get_providers():
9091
Get a list of available external authentication providers.
9192
"""
9293
return get_external_auth_providers_service()
94+
95+
96+
@router.get("/motd", response_model=MessageResponse)
97+
def get_motd():
98+
"""
99+
Get the welcome message of the day.
100+
"""
101+
return MessageResponse(message=settings.WELCOME_MESSAGE or "")

backend/app/core/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ class Settings(BaseSettings):
5252
# External Identity Providers
5353
EXTERNAL_AUTH_CONFIGS: list[ExternalAuthConfig] = []
5454

55+
# Welcome message
56+
WELCOME_MESSAGE: str | None = None
57+
5558
# MITRE settings
5659
MITRE_JSON_URL: str = "https://raw.githubusercontent.com/mitre/cti/master/enterprise-attack/enterprise-attack.json"
5760

backend/app/schemas/configuration.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,5 @@ class Configuration(BaseModel):
5959
MITRE_JSON_URL: str
6060
CUSTOM_DATA_URL: str | None
6161
ATOMIC_RED_TEAM_URL: str
62+
WELCOME_MESSAGE: str | None
6263
EXTERNAL_AUTH_CONFIGS: list[ExternalAuthConfig] | None

docs/docs/admin-guide/configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ The in-app [configuration page](../user-guide/administration.md#view-system-conf
1313
| `APPLICATION_NAME` | `RAPTR` | Name used for JWT tokens as `iss` and `aud` claims, as MFA issuer during TOTP setup and as logger name |
1414
| `LOG_LEVEL` | `INFO` | Python logging level: `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL` |
1515
| `FASTAPI_DOCUMENTATION` | `true` | Enable the OpenAPI documentation at `/docs` and `/redoc`. Set to `false` in production to hide the API docs |
16+
| `WELCOME_MESSAGE` | *(none)* | Message displayed on the login page |
1617

1718
??? bug "Inconsistent Logging"
1819
The implemented logging requires a rework. Not all relevant logs are created or stored in the DB (audit trail).

docs/docs/user-guide/administration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ The configuration page `/admin/configuration` displays all current system settin
5555

5656
Displayed settings include:
5757

58-
- **General**: application name, log level, admin email
58+
- **General**: application name, log level, admin email, welcome message
5959
- **Security**: minimum password length, OTP settings, JWT configuration, token expiry
6060
- **Database**: PostgreSQL connection details
6161
- **External Resources**: URLs for MITRE data, Atomic Red Team templates, and custom template repositories

frontend/openapi.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

frontend/src/types/schema.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,26 @@ export interface paths {
145145
patch?: never;
146146
trace?: never;
147147
};
148+
"/api/v1/auth/motd": {
149+
parameters: {
150+
query?: never;
151+
header?: never;
152+
path?: never;
153+
cookie?: never;
154+
};
155+
/**
156+
* Get Motd
157+
* @description Get the welcome message of the day.
158+
*/
159+
get: operations["get_motd_api_v1_auth_motd_get"];
160+
put?: never;
161+
post?: never;
162+
delete?: never;
163+
options?: never;
164+
head?: never;
165+
patch?: never;
166+
trace?: never;
167+
};
148168
"/api/v1/acl/": {
149169
parameters: {
150170
query?: never;
@@ -2832,6 +2852,8 @@ export interface components {
28322852
CUSTOM_DATA_URL: string | null;
28332853
/** Atomic Red Team Url */
28342854
ATOMIC_RED_TEAM_URL: string;
2855+
/** Welcome Message */
2856+
WELCOME_MESSAGE: string | null;
28352857
/** External Auth Configs */
28362858
EXTERNAL_AUTH_CONFIGS: components["schemas"]["ExternalAuthConfig"][] | null;
28372859
};
@@ -3878,6 +3900,26 @@ export interface operations {
38783900
};
38793901
};
38803902
};
3903+
get_motd_api_v1_auth_motd_get: {
3904+
parameters: {
3905+
query?: never;
3906+
header?: never;
3907+
path?: never;
3908+
cookie?: never;
3909+
};
3910+
requestBody?: never;
3911+
responses: {
3912+
/** @description Successful Response */
3913+
200: {
3914+
headers: {
3915+
[name: string]: unknown;
3916+
};
3917+
content: {
3918+
"application/json": components["schemas"]["MessageResponse"];
3919+
};
3920+
};
3921+
};
3922+
};
38813923
get_acls_api_v1_acl__get: {
38823924
parameters: {
38833925
query?: never;

frontend/src/types/zod.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ const Configuration = z
320320
MITRE_JSON_URL: z.string(),
321321
CUSTOM_DATA_URL: z.union([z.string(), z.null()]),
322322
ATOMIC_RED_TEAM_URL: z.string(),
323+
WELCOME_MESSAGE: z.union([z.string(), z.null()]),
323324
EXTERNAL_AUTH_CONFIGS: z.union([z.array(ExternalAuthConfig), z.null()]),
324325
})
325326
.passthrough();
@@ -3228,6 +3229,14 @@ Returns a provisioning URI for QR code generation.`,
32283229
},
32293230
],
32303231
},
3232+
{
3233+
method: "get",
3234+
path: "/api/v1/auth/motd",
3235+
alias: "get_motd_api_v1_auth_motd_get",
3236+
description: `Get the welcome message of the day.`,
3237+
requestFormat: "json",
3238+
response: z.object({ message: z.string() }).passthrough(),
3239+
},
32313240
{
32323241
method: "get",
32333242
path: "/api/v1/auth/providers",

frontend/src/views/LoginView.vue

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { toTypedSchema } from '@vee-validate/zod';
33
import { useForm } from 'vee-validate';
44
import { onMounted, ref } from 'vue';
55
import { useRouter } from 'vue-router';
6+
import { Info } from 'lucide-vue-next';
67
import { Button } from '@/components/ui/button';
78
import {
89
Card,
@@ -20,18 +21,29 @@ import {
2021
FormMessage,
2122
} from '@/components/ui/form';
2223
import { Input } from '@/components/ui/input';
24+
import { api } from '@/services/api';
2325
import { useAuthStore } from '@/stores/auth';
2426
import { schemas } from '@/types/zod';
2527
2628
const router = useRouter();
2729
const authStore = useAuthStore();
2830
const loading = ref(false);
31+
const motd = ref<string | null>(null);
2932
3033
const usernameInput = ref<InstanceType<typeof Input> | null>(null);
3134
32-
onMounted(() => {
35+
onMounted(async () => {
3336
authStore.fetchProviders();
3437
usernameInput.value?.$el?.focus();
38+
39+
try {
40+
const response = await api.get<{ message: string | null }>('/auth/motd');
41+
if (response.data.message) {
42+
motd.value = response.data.message;
43+
}
44+
} catch (e) {
45+
// Silently ignore if MOTD fetch fails
46+
}
3547
});
3648
3749
const formSchema = toTypedSchema(
@@ -68,7 +80,12 @@ const onSubmit = form.handleSubmit(async (values) => {
6880
</script>
6981

7082
<template>
71-
<div class="flex items-center justify-center min-h-screen p-4">
83+
<div class="flex flex-col items-center justify-center min-h-screen p-4">
84+
<div v-if="motd" class="w-full max-w-md mb-6 p-4 rounded-lg bg-blue-50 dark:bg-blue-950 border border-blue-200 dark:border-blue-900 text-blue-800 dark:text-blue-200 text-sm flex items-start shadow-sm">
85+
<Info class="w-5 h-5 mr-3 shrink-0 mt-0.5" />
86+
<div class="leading-relaxed whitespace-pre-wrap">{{ motd }}</div>
87+
</div>
88+
7289
<Card class="w-full max-w-md">
7390
<CardHeader class="space-y-1">
7491
<CardTitle class="text-2xl font-bold text-center">Sign In</CardTitle>

frontend/src/views/admin/ConfigurationView.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@
4444
<span class="text-sm font-medium">Admin User</span>
4545
<span class="text-sm font-mono text-muted-foreground">{{ configuration.ADMIN_EMAIL }}</span>
4646
</div>
47+
<div class="grid grid-cols-2 items-center gap-4">
48+
<span class="text-sm font-medium">Welcome Message</span>
49+
<span class="text-sm font-mono text-muted-foreground whitespace-pre-wrap">{{ configuration.WELCOME_MESSAGE || 'None' }}</span>
50+
</div>
4751
</CardContent>
4852
</Card>
4953

0 commit comments

Comments
 (0)