UNPKG

@dudousxd/nestjs-telescope

Version:

Laravel Telescope-style observability console for NestJS — core: watchers, recorder, correlation, SQLite store, headless API.

108 lines 4.82 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; // packages/core/src/nest/telescope.guard.ts import { Inject, Injectable, UnauthorizedException, } from '@nestjs/common'; import { attachSession, readCookieHeader } from '../auth/auth-request.js'; import { parseCookieHeader } from '../auth/cookie-header.js'; import { SESSION_COOKIE_NAME, issueSessionCookie } from '../auth/session-cookie-io.js'; import { verifySessionCookie } from '../auth/session-cookie.js'; import { TELESCOPE_CONFIG, TELESCOPE_DASHBOARD_AUTH, TELESCOPE_OPTIONS, } from './telescope.options.js'; let TelescopeGuard = class TelescopeGuard { options; dashboardAuth; config; constructor(options, dashboardAuth = null, config = null) { this.options = options; this.dashboardAuth = dashboardAuth; this.config = config; } async canActivate(context) { const http = context.switchToHttp(); const request = http.getRequest(); // Cookie-session gate: when configured, a valid session cookie is REQUIRED // for every guarded route (the auth endpoints live on a separate, ungated // controller). The session is attached to the request, then `authorizer` // still runs (AND semantics) below. if (this.dashboardAuth) { const session = this.verifyRequestSession(request); if (!session) { // Absent/invalid/expired cookie => 401 (not 403): the SPA reads this as // "log in", distinct from authorizer's 403 "logged in but forbidden". throw new UnauthorizedException(); } attachSession(request, session); this.maybeRenew(http.getResponse(), request, session); return this.runAuthorizer(request); } if (this.options.authorizer) { return this.runAuthorizer(request); } // Safe default: open in dev, closed in production. An unset NODE_ENV is // treated as non-production (local/dev context). return process.env.NODE_ENV !== 'production'; } verifyRequestSession(request) { const auth = this.dashboardAuth; if (!auth) return null; const cookieValue = parseCookieHeader(readCookieHeader(request))[SESSION_COOKIE_NAME]; if (cookieValue === undefined) return null; return verifySessionCookie(cookieValue, { secret: auth.secret }); } /** * Sliding renewal: when a valid cookie is past 50% of its TTL, re-issue a * fresh one so active users never get logged out mid-session. Appends a new * Set-Cookie (preserving any others already on the response). */ maybeRenew(response, request, session) { const auth = this.dashboardAuth; if (!auth) return; const now = Date.now(); if (now - session.iat <= auth.ttlMs / 2) return; issueSessionCookie({ id: session.sub, ...(session.name !== undefined ? { name: session.name } : {}), roles: session.roles, }, { auth, telescopePath: this.config?.path ?? 'telescope', request, response, now, }); } async runAuthorizer(request) { if (!this.options.authorizer) return true; try { return await this.options.authorizer({ request }); } catch { // Fail closed: a throwing authorizer denies access (clean 403), // never accidentally grants it or surfaces a 500. return false; } } }; TelescopeGuard = __decorate([ Injectable(), __param(0, Inject(TELESCOPE_OPTIONS)), __param(1, Inject(TELESCOPE_DASHBOARD_AUTH)), __param(2, Inject(TELESCOPE_CONFIG)), __metadata("design:paramtypes", [Object, Object, Object]) ], TelescopeGuard); export { TelescopeGuard }; //# sourceMappingURL=telescope.guard.js.map