From d36e1bfed26715c25fd5a3af3ed31198cf9687d4 Mon Sep 17 00:00:00 2001 From: erdemcaygor Date: Mon, 15 Sep 2025 20:27:17 +0300 Subject: [PATCH] refactoring --- npm/ng-packs/apps/dev-app/src/server.ts | 15 +++++-- npm/ng-packs/package.json | 1 - .../packages/core/src/lib/services/index.ts | 1 + .../services/server-cookie-parser.service.ts | 44 +++++++++++++++++++ .../core/src/lib/tokens/ssr-state.token.ts | 7 ++- 5 files changed, 62 insertions(+), 6 deletions(-) create mode 100644 npm/ng-packs/packages/core/src/lib/services/server-cookie-parser.service.ts diff --git a/npm/ng-packs/apps/dev-app/src/server.ts b/npm/ng-packs/apps/dev-app/src/server.ts index 69a3cdf856..eac20ebd15 100644 --- a/npm/ng-packs/apps/dev-app/src/server.ts +++ b/npm/ng-packs/apps/dev-app/src/server.ts @@ -5,11 +5,11 @@ import { writeResponseToNodeResponse, } from '@angular/ssr/node'; import express from 'express'; -import cookieParser from 'cookie-parser'; import { dirname, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import {environment} from './environments/environment'; import * as oidc from 'openid-client'; +import { ServerCookieParser } from '@abp/ng.core'; if (environment.production === false) { process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = "0"; @@ -21,7 +21,7 @@ const browserDistFolder = resolve(serverDistFolder, '../browser'); const app = express(); const angularApp = new AngularNodeAppEngine(); -const ISSUER = new URL(environment.oAuthConfig.issuer); // OIDC issuer +const ISSUER = new URL(environment.oAuthConfig.issuer); const CLIENT_ID = environment.oAuthConfig.clientId; const REDIRECT_URI = environment.oAuthConfig.redirectUri; const SCOPE = environment.oAuthConfig.scope; @@ -30,7 +30,7 @@ const config = await oidc.discovery(ISSUER, CLIENT_ID, /* client_secret */ undef const secureCookie = { httpOnly: true, sameSite: 'lax' as const, secure: environment.production, path: '/' }; const tokenCookie = { ...secureCookie, httpOnly: false }; -app.use(cookieParser()); +app.use(ServerCookieParser.middleware()); const sessions = new Map(); @@ -159,7 +159,14 @@ app.use( app.use((req, res, next) => { angularApp .handle(req) - .then(response => (response ? writeResponseToNodeResponse(response, res) : next())) + .then(response => { + if (response) { + res.cookie('ssrEnabled', 'true', {...secureCookie, httpOnly: false}); + return writeResponseToNodeResponse(response, res); + } else { + return next() + } + }) .catch(next); }); diff --git a/npm/ng-packs/package.json b/npm/ng-packs/package.json index 2065286735..c13d61058a 100644 --- a/npm/ng-packs/package.json +++ b/npm/ng-packs/package.json @@ -145,7 +145,6 @@ ] }, "dependencies": { - "cookie-parser": "^1.4.7", "openid-client": "^6.6.4" } } diff --git a/npm/ng-packs/packages/core/src/lib/services/index.ts b/npm/ng-packs/packages/core/src/lib/services/index.ts index e6821009fe..1e9d45fe20 100644 --- a/npm/ng-packs/packages/core/src/lib/services/index.ts +++ b/npm/ng-packs/packages/core/src/lib/services/index.ts @@ -28,3 +28,4 @@ export * from './time.service'; export * from './ssr.service'; export * from './cookie-storage.service'; export * from './dom-strategy.service'; +export * from './server-cookie-parser.service'; diff --git a/npm/ng-packs/packages/core/src/lib/services/server-cookie-parser.service.ts b/npm/ng-packs/packages/core/src/lib/services/server-cookie-parser.service.ts new file mode 100644 index 0000000000..4b807ddf30 --- /dev/null +++ b/npm/ng-packs/packages/core/src/lib/services/server-cookie-parser.service.ts @@ -0,0 +1,44 @@ +export class ServerCookieParser { + static parse(cookieHeader: string): { [key: string]: string } { + const cookies: { [key: string]: string } = {}; + + if (!cookieHeader) return cookies; + + try { + cookieHeader.split(';').forEach(cookie => { + const parts = cookie.trim().split('='); + if (parts.length >= 2) { + const name = parts[0].trim(); + const value = parts.slice(1).join('='); + + if (name) { + try { + cookies[name] = decodeURIComponent(value); + } catch (e) { + cookies[name] = value; + } + } + } + }); + } catch (error) { + console.error('Error parsing cookies:', error); + } + + return cookies; + } + + static middleware() { + return (req: any, res: any, next: any) => { + req.cookies = ServerCookieParser.parse(req.headers.cookie || ''); + next(); + }; + } + + static getCookie(req: any, name: string): string | undefined { + const cookieHeader = req.headers.cookie; + if (!cookieHeader) return undefined; + + const cookies = ServerCookieParser.parse(cookieHeader); + return cookies[name]; + } +} diff --git a/npm/ng-packs/packages/core/src/lib/tokens/ssr-state.token.ts b/npm/ng-packs/packages/core/src/lib/tokens/ssr-state.token.ts index a9a4448149..3b82c747ef 100644 --- a/npm/ng-packs/packages/core/src/lib/tokens/ssr-state.token.ts +++ b/npm/ng-packs/packages/core/src/lib/tokens/ssr-state.token.ts @@ -1,5 +1,6 @@ import { inject, InjectionToken, makeStateKey, PLATFORM_ID, TransferState } from '@angular/core'; import { isPlatformBrowser } from '@angular/common'; +import { AbpCookieStorageService } from '../services'; export const SSR_FLAG = makeStateKey('SSR_FLAG'); @@ -7,8 +8,12 @@ export const APP_STARTED_WITH_SSR = new InjectionToken('APP_STARTED_WIT providedIn: 'root', factory: () => { const platformId = inject(PLATFORM_ID); + const cookieService = inject(AbpCookieStorageService); if (!isPlatformBrowser(platformId)) return true; const ts = inject(TransferState); - return ts.get(SSR_FLAG, false); + const ssrEnabled = cookieService.getItem('ssrEnabled'); + // Remove the cookie after reading its value because it's only needed once + cookieService.removeItem('ssrEnabled'); + return ts.get(SSR_FLAG, false) || ssrEnabled === 'true'; }, });