mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 21:20:57 +00:00
64 lines
2.1 KiB
TypeScript
64 lines
2.1 KiB
TypeScript
/**
|
|
* Reading the authenticated staff member off the request.
|
|
*
|
|
* `JwtGuard` (from `@tria-plc/api-common`) puts the decoded IAM user on `request.user`.
|
|
* Sibling controllers reach for `req.user?.id ?? req.user?.sub`, because the shape differs
|
|
* slightly between token versions. This module centralises that so callers get a small,
|
|
* typed value object instead of an `any` bag.
|
|
*/
|
|
|
|
/** Bilingual name as IAM stores it. */
|
|
interface ActingUserName {
|
|
en?: string;
|
|
am?: string;
|
|
}
|
|
|
|
/** The slice of `request.user` this app actually reads. */
|
|
export interface ActingUserClaims {
|
|
id?: string;
|
|
/** Older tokens carry the subject as `sub` rather than `id`. */
|
|
sub?: string;
|
|
name?: ActingUserName | string | null;
|
|
username?: string;
|
|
email?: string;
|
|
}
|
|
|
|
/** The minimal Express request shape needed to reach the authenticated user. */
|
|
export interface RequestWithActingUser {
|
|
user?: ActingUserClaims;
|
|
}
|
|
|
|
/** Who performed an action, resolved once at write time so readers need no IAM lookup. */
|
|
export interface ActingUser {
|
|
/** IAM user id. */
|
|
id: string;
|
|
/** Human-readable name, denormalized alongside the id. */
|
|
name: string;
|
|
}
|
|
|
|
/**
|
|
* Resolves the acting staff member from a guarded request.
|
|
*
|
|
* Returns `null` when no user is attached — callers decide what that means. Endpoints behind
|
|
* `@PassengerStaff(...)` always have one, since the guard rejects anonymous requests; system
|
|
* paths (ticketing, cleanup jobs) legitimately have none and record themselves explicitly.
|
|
*/
|
|
export function resolveActingUser(req: RequestWithActingUser): ActingUser | null {
|
|
const claims = req.user;
|
|
const id = claims?.id ?? claims?.sub;
|
|
if (!id) return null;
|
|
|
|
return { id, name: resolveActingUserName(claims) };
|
|
}
|
|
|
|
function resolveActingUserName(claims: ActingUserClaims | undefined): string {
|
|
if (!claims) return 'Unknown';
|
|
const { name } = claims;
|
|
if (typeof name === 'string' && name.trim()) return name.trim();
|
|
if (name && typeof name === 'object') {
|
|
const localized = name.en?.trim() || name.am?.trim();
|
|
if (localized) return localized;
|
|
}
|
|
return claims.username?.trim() || claims.email?.trim() || 'Unknown';
|
|
}
|