freeze: just commit to have a history track, but this code is not working yet

master
Guillermo Pages 3 months ago
parent a032f9b6bf
commit 9f2176cd4b

@ -1,15 +1,15 @@
# swissoid-back # swissoid-back
SwissOID authentication package for Node.js backends. Provides reusable authentication components for integrating SwissOID (OpenID Connect) authentication into Node.js applications. SwissOID authentication backend for Node.js applications. Provides reusable OIDC authentication components for integrating with SwissOID (Swiss eID).
## Features ## Features
- 🔐 Complete OIDC Authorization Code Flow implementation - 🔐 Full OIDC Authorization Code Flow implementation
- 🍪 Secure cookie-based session management - 🍪 Session management with Redis
- 🔑 JWT verification with JWKS support - 🔑 JWT verification with JWKS
- 📦 Dependency Injection ready (di-why compatible) - 🎯 Built for di-why dependency injection
- 🚀 TypeScript support with full type definitions - 📦 Reusable authentication components
- ⚡ Redis-based session storage - 🔄 Configurable via environment variables or appConfig
## Installation ## Installation
@ -17,169 +17,137 @@ SwissOID authentication package for Node.js backends. Provides reusable authenti
npm install swissoid-back npm install swissoid-back
``` ```
## Usage ## Requirements
### Basic Setup with Dependency Injection - Node.js >= 18
- Redis server for session storage
- SwissOID client credentials
```typescript ## Usage
import {
oidcRoutesLDEGen,
swissoidSessionServiceLDEGen,
cookieManagerLDEGen,
swissoidJWTVerifierLDEGen,
redisClientLDEGen
} from 'swissoid-back';
import DiContainer from 'di-why';
const container = new DiContainer({ ### With express-knifey / graphql-knifey (Recommended)
load: {
// Redis client for session storage
redisClient: redisClientLDEGen(),
// Session service swissoid-back integrates seamlessly with express-knifey's middleware system:
sessionService: swissoidSessionServiceLDEGen(),
// Cookie manager ```typescript
cookieManager: cookieManagerLDEGen({ import DiContainer, { mergeLDs } from 'di-why';
domain: '.example.com', import { apolloSubgraphServerModularLDGen } from 'graphql-knifey';
sessionName: 'app_session' import { swissoidAuthLoadDict } from 'swissoid-back';
// Define middleware configuration including OIDC routes
const middlewareConfig = {
'/graphql': [
{ name: 'expressCorsMiddleware', priority: 90 },
{ name: 'expressCookieParserMiddleware', priority: 80 },
{ name: 'expressBodyParserMiddleware', priority: 70 },
{ name: 'expressGraphqlMiddleware', required: true, priority: -100 },
],
'*': [
// Add OIDC routes as global middleware
{ name: 'oidcStandardRoutesMiddleware', priority: 50 },
]
};
const diContainer = new DiContainer({
load: mergeLDs(
// GraphQL server with middleware config
apolloSubgraphServerModularLDGen({
resolvers,
typeDefs,
middlewareConfig
}), }),
// JWT verifier // SwissOID authentication components
jwtVerifier: swissoidJWTVerifierLDEGen(), swissoidAuthLoadDict,
// OIDC routes // Your other loaders...
oidcRoutes: oidcRoutesLDEGen({ )
clientId: 'your-client-id',
cookieDomain: '.example.com'
})
}
}); });
``` ```
### Express Integration ### Direct Express Usage
```typescript
import { swissoidAuthLoadDict } from 'swissoid-back';
// Load OIDC routes directly (this will mount them on the express app)
await diContainer.load('oidcStandardRoutes');
```
### AppConfig Integration
swissoid-back provides an appConfigMap that can be merged with your application's configuration:
```typescript ```typescript
import express from 'express'; import { swissoidMergeAppConfigMap } from 'swissoid-back';
import cookieParser from 'cookie-parser';
const merged = swissoidMergeAppConfigMap(yourAppConfigMap);
const app = express(); export type AppConfig = ReturnType<typeof merged>;
// Required middleware
app.use(cookieParser());
// Mount OIDC routes
const oidcRoutes = await container.get('oidcRoutes');
app.use(oidcRoutes);
// Routes provided:
// GET /login - Initiates OIDC flow
// POST /oidc/callback - Handles callback from IdP
// GET /oidc/finalize - Sets cookies in first-party context
// GET /auth/status - Returns authentication status
// GET /auth/userinfo - Returns user information
// GET /auth/logout - Destroys session
// POST /auth/logout - Destroys session (JSON response)
``` ```
### Configuration ### Configuration
Required environment variables: Create a `.env` file with the required configuration (see `.env.example` for all options):
```bash ```env
# SwissOID Configuration # SwissOID Configuration
SWISSOID_ISSUER=https://api.swissoid.com SWISSOID_ISSUER=https://api.swissoid.com
SWISSOID_CLIENT_ID=your-client-id SWISSOID_CLIENT_ID=your-client-id
SWISSOID_CLIENT_SECRET=your-client-secret SWISSOID_CLIENT_SECRET=your-client-secret
SWISSOID_TOKEN_ENDPOINT=https://api.swissoid.com/token SWISSOID_TOKEN_ENDPOINT=https://api.swissoid.com/token
SWISSOID_JWKS_URI=https://api.swissoid.com/.well-known/jwks.json SWISSOID_JWKS_URI=https://api.swissoid.com/.well-known/jwks.json
SWISSOID_AUTHORIZE_ENDPOINT=https://api.swissoid.com/authorize
# RP Configuration # Redis Configuration
RP_CALLBACK_URL=https://your-app.com/oidc/callback REDIS_HOST=localhost
RP_COOKIE_DOMAIN=.your-app.com REDIS_PORT=6379
RP_FRONTEND_URL=https://app.your-app.com
# Session Configuration # Session Configuration
SESSION_COOKIE_NAME=app_session SESSION_COOKIE_NAME=connect.sid
SESSION_SECRET=your-session-secret SESSION_SECRET=your-session-secret
STATE_SIGNING_SECRET=your-state-signing-secret
# Redis # RP Configuration
REDIS_URL=redis://localhost:6379 RP_FRONTEND_URL=http://localhost:3000
COOKIE_DOMAIN=localhost
OIDC_REDIRECT_BASE_URL=http://localhost:3668
``` ```
### Manual Usage (without DI) ## Routes
```typescript
import { createOIDCRoutes, SwissOIDSessionService, CookieManager } from 'swissoid-back';
import Redis from 'ioredis';
// Create Redis client The package provides the following OIDC routes when loaded:
const redisClient = new Redis('redis://localhost:6379');
// Create session service - `GET /login` - Initiates OIDC authorization flow
const sessionService = new SwissOIDSessionService(redisClient, console); - `POST /oidc/callback` - Handles OIDC callback from SwissOID
- `POST /oidc/finalize` - Completes authentication and sets session
- `GET /auth/status` - Returns current authentication status
- `POST /auth/logout` - Logs out the user
// Create cookie manager ## Components
const cookieManager = new CookieManager({
domain: '.example.com',
sessionName: 'app_session',
secureCookie: true,
sameSite: 'lax'
});
// Create OIDC routes
const oidcRoutes = createOIDCRoutes({
logger: console,
sessionService,
redisClient,
issuer: 'https://api.swissoid.com',
clientId: 'your-client-id',
// ... other config
});
app.use(oidcRoutes); The `swissoidAuthLoadDict` includes:
```
## API Reference - **redisClient**: Redis connection for session storage
- **sessionService**: Session management service
- **cookieManager**: Cookie handling utilities
- **oidcStandardRoutes**: Express router with OIDC endpoints
- **oidcStandardRoutesMiddleware**: Middleware-compatible version for express-knifey integration
- **swissoidAppConfigMap**: AppConfig map with priority 60
### Components ## Exports
- **oidcRoutesLDEGen**: Loader for OIDC route handlers ```typescript
- **swissoidSessionServiceLDEGen**: Loader for session management service // Main LoadDict for di-why
- **cookieManagerLDEGen**: Loader for cookie operations import { swissoidAuthLoadDict } from 'swissoid-back';
- **swissoidJWTVerifierLDEGen**: Loader for JWT verification
- **redisClientLDEGen**: Loader for Redis client
### Types // AppConfig utilities
import { swissoidMergeAppConfigMap } from 'swissoid-back';
```typescript // Individual loaders if needed
interface OIDCConfig { import {
issuer: string; sessionService,
clientId: string; cookieManager,
clientSecret?: string; oidcStandardRoutes,
tokenEndpoint: string; oidcStandardRoutesMiddleware
jwksUri: string; } from 'swissoid-back';
authorizeEndpoint: string;
callbackUrl: string;
cookieDomain: string;
frontendUrl: string;
sessionCookieName: string;
sessionSecret: string;
stateSigningSecret: string;
}
interface SessionData {
sub: string;
email?: string;
name?: string;
iat: number;
exp: number;
createdAt?: number;
lastAccessedAt?: number;
metadata?: Record<string, any>;
}
``` ```
## License ## License

529
package-lock.json generated

@ -13,7 +13,7 @@
"@types/node-fetch": "^2.6.13", "@types/node-fetch": "^2.6.13",
"cookie-parser": "^1.4.7", "cookie-parser": "^1.4.7",
"di-why": "^0.20.0", "di-why": "^0.20.0",
"express": "^5.1.0", "express": "^4.21.2",
"ioredis": "^5.7.0", "ioredis": "^5.7.0",
"jose": "^6.1.0", "jose": "^6.1.0",
"node-fetch": "^3.3.2", "node-fetch": "^3.3.2",
@ -21,7 +21,7 @@
}, },
"devDependencies": { "devDependencies": {
"@types/cookie-parser": "^1.4.9", "@types/cookie-parser": "^1.4.9",
"@types/express": "^5.0.3", "@types/express": "^4.17.21",
"@types/jest": "^30.0.0", "@types/jest": "^30.0.0",
"@types/node": "^18.0.0", "@types/node": "^18.0.0",
"jest": "^30.1.3", "jest": "^30.1.3",
@ -1214,14 +1214,15 @@
} }
}, },
"node_modules/@types/express": { "node_modules/@types/express": {
"version": "5.0.3", "version": "4.17.23",
"resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.3.tgz", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.23.tgz",
"integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==", "integrity": "sha512-Crp6WY9aTYP3qPi2wGDo9iUe/rceX01UMhnF1jmwDcKCFM6cx7YhGP/Mpr3y9AASpfHixIG0E6azCcL5OcDHsQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@types/body-parser": "*", "@types/body-parser": "*",
"@types/express-serve-static-core": "^5.0.0", "@types/express-serve-static-core": "^4.17.33",
"@types/qs": "*",
"@types/serve-static": "*" "@types/serve-static": "*"
} }
}, },
@ -1237,6 +1238,19 @@
"@types/send": "*" "@types/send": "*"
} }
}, },
"node_modules/@types/express/node_modules/@types/express-serve-static-core": {
"version": "4.19.6",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.6.tgz",
"integrity": "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*",
"@types/qs": "*",
"@types/range-parser": "*",
"@types/send": "*"
}
},
"node_modules/@types/http-errors": { "node_modules/@types/http-errors": {
"version": "2.0.5", "version": "2.0.5",
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz",
@ -1642,34 +1656,13 @@
] ]
}, },
"node_modules/accepts": { "node_modules/accepts": {
"version": "2.0.0", "version": "1.3.8",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
"integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
"license": "MIT",
"dependencies": {
"mime-types": "^3.0.0",
"negotiator": "^1.0.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/accepts/node_modules/mime-db": {
"version": "1.54.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/accepts/node_modules/mime-types": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"mime-db": "^1.54.0" "mime-types": "~2.1.34",
"negotiator": "0.6.3"
}, },
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@ -1744,6 +1737,12 @@
"sprintf-js": "~1.0.2" "sprintf-js": "~1.0.2"
} }
}, },
"node_modules/array-flatten": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
"license": "MIT"
},
"node_modules/asynckit": { "node_modules/asynckit": {
"version": "0.4.0", "version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@ -1869,25 +1868,44 @@
} }
}, },
"node_modules/body-parser": { "node_modules/body-parser": {
"version": "2.2.0", "version": "1.20.3",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
"integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"bytes": "^3.1.2", "bytes": "3.1.2",
"content-type": "^1.0.5", "content-type": "~1.0.5",
"debug": "^4.4.0", "debug": "2.6.9",
"http-errors": "^2.0.0", "depd": "2.0.0",
"iconv-lite": "^0.6.3", "destroy": "1.2.0",
"on-finished": "^2.4.1", "http-errors": "2.0.0",
"qs": "^6.14.0", "iconv-lite": "0.4.24",
"raw-body": "^3.0.0", "on-finished": "2.4.1",
"type-is": "^2.0.0" "qs": "6.13.0",
"raw-body": "2.5.2",
"type-is": "~1.6.18",
"unpipe": "1.0.0"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
} }
}, },
"node_modules/body-parser/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/body-parser/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
"node_modules/brace-expansion": { "node_modules/brace-expansion": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
@ -2249,9 +2267,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/content-disposition": { "node_modules/content-disposition": {
"version": "1.0.0", "version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
"integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"safe-buffer": "5.2.1" "safe-buffer": "5.2.1"
@ -2397,6 +2415,16 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/destroy": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
"license": "MIT",
"engines": {
"node": ">= 0.8",
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/detect-newline": { "node_modules/detect-newline": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz",
@ -2633,77 +2661,75 @@
} }
}, },
"node_modules/express": { "node_modules/express": {
"version": "5.1.0", "version": "4.21.2",
"resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
"integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"accepts": "^2.0.0", "accepts": "~1.3.8",
"body-parser": "^2.2.0", "array-flatten": "1.1.1",
"content-disposition": "^1.0.0", "body-parser": "1.20.3",
"content-type": "^1.0.5", "content-disposition": "0.5.4",
"cookie": "^0.7.1", "content-type": "~1.0.4",
"cookie-signature": "^1.2.1", "cookie": "0.7.1",
"debug": "^4.4.0", "cookie-signature": "1.0.6",
"encodeurl": "^2.0.0", "debug": "2.6.9",
"escape-html": "^1.0.3", "depd": "2.0.0",
"etag": "^1.8.1", "encodeurl": "~2.0.0",
"finalhandler": "^2.1.0", "escape-html": "~1.0.3",
"fresh": "^2.0.0", "etag": "~1.8.1",
"http-errors": "^2.0.0", "finalhandler": "1.3.1",
"merge-descriptors": "^2.0.0", "fresh": "0.5.2",
"mime-types": "^3.0.0", "http-errors": "2.0.0",
"on-finished": "^2.4.1", "merge-descriptors": "1.0.3",
"once": "^1.4.0", "methods": "~1.1.2",
"parseurl": "^1.3.3", "on-finished": "2.4.1",
"proxy-addr": "^2.0.7", "parseurl": "~1.3.3",
"qs": "^6.14.0", "path-to-regexp": "0.1.12",
"range-parser": "^1.2.1", "proxy-addr": "~2.0.7",
"router": "^2.2.0", "qs": "6.13.0",
"send": "^1.1.0", "range-parser": "~1.2.1",
"serve-static": "^2.2.0", "safe-buffer": "5.2.1",
"statuses": "^2.0.1", "send": "0.19.0",
"type-is": "^2.0.1", "serve-static": "1.16.2",
"vary": "^1.1.2" "setprototypeof": "1.2.0",
"statuses": "2.0.1",
"type-is": "~1.6.18",
"utils-merge": "1.0.1",
"vary": "~1.1.2"
}, },
"engines": { "engines": {
"node": ">= 18" "node": ">= 0.10.0"
}, },
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
"url": "https://opencollective.com/express" "url": "https://opencollective.com/express"
} }
}, },
"node_modules/express/node_modules/cookie-signature": { "node_modules/express/node_modules/cookie": {
"version": "1.2.2", "version": "0.7.1",
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
"integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
"license": "MIT",
"engines": {
"node": ">=6.6.0"
}
},
"node_modules/express/node_modules/mime-db": {
"version": "1.54.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/express/node_modules/mime-types": { "node_modules/express/node_modules/debug": {
"version": "3.0.1", "version": "2.6.9",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"mime-db": "^1.54.0" "ms": "2.0.0"
},
"engines": {
"node": ">= 0.6"
} }
}, },
"node_modules/express/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
"node_modules/fast-json-stable-stringify": { "node_modules/fast-json-stable-stringify": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@ -2758,22 +2784,38 @@
} }
}, },
"node_modules/finalhandler": { "node_modules/finalhandler": {
"version": "2.1.0", "version": "1.3.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
"integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"debug": "^4.4.0", "debug": "2.6.9",
"encodeurl": "^2.0.0", "encodeurl": "~2.0.0",
"escape-html": "^1.0.3", "escape-html": "~1.0.3",
"on-finished": "^2.4.1", "on-finished": "2.4.1",
"parseurl": "^1.3.3", "parseurl": "~1.3.3",
"statuses": "^2.0.1" "statuses": "2.0.1",
"unpipe": "~1.0.0"
}, },
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/finalhandler/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/finalhandler/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
"node_modules/find-up": { "node_modules/find-up": {
"version": "4.1.0", "version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
@ -2856,12 +2898,12 @@
} }
}, },
"node_modules/fresh": { "node_modules/fresh": {
"version": "2.0.0", "version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
"integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.6"
} }
}, },
"node_modules/fs.realpath": { "node_modules/fs.realpath": {
@ -3109,15 +3151,6 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/http-errors/node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/human-signals": { "node_modules/human-signals": {
"version": "2.1.0", "version": "2.1.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
@ -3129,12 +3162,12 @@
} }
}, },
"node_modules/iconv-lite": { "node_modules/iconv-lite": {
"version": "0.6.3", "version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0" "safer-buffer": ">= 2.1.2 < 3"
}, },
"engines": { "engines": {
"node": ">=0.10.0" "node": ">=0.10.0"
@ -3258,12 +3291,6 @@
"node": ">=0.12.0" "node": ">=0.12.0"
} }
}, },
"node_modules/is-promise": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
"license": "MIT"
},
"node_modules/is-stream": { "node_modules/is-stream": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
@ -4168,22 +4195,19 @@
} }
}, },
"node_modules/media-typer": { "node_modules/media-typer": {
"version": "1.1.0", "version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.6"
} }
}, },
"node_modules/merge-descriptors": { "node_modules/merge-descriptors": {
"version": "2.0.0", "version": "1.0.3",
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
"integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
"license": "MIT", "license": "MIT",
"engines": {
"node": ">=18"
},
"funding": { "funding": {
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
@ -4195,6 +4219,15 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
"integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/micromatch": { "node_modules/micromatch": {
"version": "4.0.8", "version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
@ -4209,6 +4242,18 @@
"node": ">=8.6" "node": ">=8.6"
} }
}, },
"node_modules/mime": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
"license": "MIT",
"bin": {
"mime": "cli.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/mime-db": { "node_modules/mime-db": {
"version": "1.52.0", "version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
@ -4306,9 +4351,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/negotiator": { "node_modules/negotiator": {
"version": "1.0.0", "version": "0.6.3",
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
"integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@ -4424,6 +4469,7 @@
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dev": true,
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"wrappy": "1" "wrappy": "1"
@ -4590,14 +4636,10 @@
"license": "ISC" "license": "ISC"
}, },
"node_modules/path-to-regexp": { "node_modules/path-to-regexp": {
"version": "8.3.0", "version": "0.1.12",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
"integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==", "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==",
"license": "MIT", "license": "MIT"
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
}, },
"node_modules/picocolors": { "node_modules/picocolors": {
"version": "1.1.1", "version": "1.1.1",
@ -4701,12 +4743,12 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/qs": { "node_modules/qs": {
"version": "6.14.0", "version": "6.13.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
"integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"side-channel": "^1.1.0" "side-channel": "^1.0.6"
}, },
"engines": { "engines": {
"node": ">=0.6" "node": ">=0.6"
@ -4725,34 +4767,18 @@
} }
}, },
"node_modules/raw-body": { "node_modules/raw-body": {
"version": "3.0.1", "version": "2.5.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.1.tgz", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
"integrity": "sha512-9G8cA+tuMS75+6G/TzW8OtLzmBDMo8p1JRxN5AZ+LAp8uxGA8V8GZm4GQ4/N5QNQEnLmg6SS7wyuSmbKepiKqA==", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"bytes": "3.1.2", "bytes": "3.1.2",
"http-errors": "2.0.0", "http-errors": "2.0.0",
"iconv-lite": "0.7.0", "iconv-lite": "0.4.24",
"unpipe": "1.0.0" "unpipe": "1.0.0"
}, },
"engines": { "engines": {
"node": ">= 0.10" "node": ">= 0.8"
}
},
"node_modules/raw-body/node_modules/iconv-lite": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
"integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
} }
}, },
"node_modules/react-is": { "node_modules/react-is": {
@ -4832,22 +4858,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/router": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
"integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
"license": "MIT",
"dependencies": {
"debug": "^4.4.0",
"depd": "^2.0.0",
"is-promise": "^4.0.0",
"parseurl": "^1.3.3",
"path-to-regexp": "^8.0.0"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/safe-buffer": { "node_modules/safe-buffer": {
"version": "5.2.1", "version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@ -4885,61 +4895,66 @@
} }
}, },
"node_modules/send": { "node_modules/send": {
"version": "1.2.0", "version": "0.19.0",
"resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
"integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"debug": "^4.3.5", "debug": "2.6.9",
"encodeurl": "^2.0.0", "depd": "2.0.0",
"escape-html": "^1.0.3", "destroy": "1.2.0",
"etag": "^1.8.1", "encodeurl": "~1.0.2",
"fresh": "^2.0.0", "escape-html": "~1.0.3",
"http-errors": "^2.0.0", "etag": "~1.8.1",
"mime-types": "^3.0.1", "fresh": "0.5.2",
"ms": "^2.1.3", "http-errors": "2.0.0",
"on-finished": "^2.4.1", "mime": "1.6.0",
"range-parser": "^1.2.1", "ms": "2.1.3",
"statuses": "^2.0.1" "on-finished": "2.4.1",
"range-parser": "~1.2.1",
"statuses": "2.0.1"
}, },
"engines": { "engines": {
"node": ">= 18" "node": ">= 0.8.0"
} }
}, },
"node_modules/send/node_modules/mime-db": { "node_modules/send/node_modules/debug": {
"version": "1.54.0", "version": "2.6.9",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"license": "MIT", "license": "MIT",
"engines": { "dependencies": {
"node": ">= 0.6" "ms": "2.0.0"
} }
}, },
"node_modules/send/node_modules/mime-types": { "node_modules/send/node_modules/debug/node_modules/ms": {
"version": "3.0.1", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT", "license": "MIT"
"dependencies": {
"mime-db": "^1.54.0"
}, },
"node_modules/send/node_modules/encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
"license": "MIT",
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.8"
} }
}, },
"node_modules/serve-static": { "node_modules/serve-static": {
"version": "2.2.0", "version": "1.16.2",
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
"integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"encodeurl": "^2.0.0", "encodeurl": "~2.0.0",
"escape-html": "^1.0.3", "escape-html": "~1.0.3",
"parseurl": "^1.3.3", "parseurl": "~1.3.3",
"send": "^1.2.0" "send": "0.19.0"
}, },
"engines": { "engines": {
"node": ">= 18" "node": ">= 0.8.0"
} }
}, },
"node_modules/setprototypeof": { "node_modules/setprototypeof": {
@ -5108,9 +5123,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/statuses": { "node_modules/statuses": {
"version": "2.0.2", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 0.8" "node": ">= 0.8"
@ -5520,35 +5535,13 @@
} }
}, },
"node_modules/type-is": { "node_modules/type-is": {
"version": "2.0.1", "version": "1.6.18",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
"integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"content-type": "^1.0.5", "media-typer": "0.3.0",
"media-typer": "^1.1.0", "mime-types": "~2.1.24"
"mime-types": "^3.0.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/type-is/node_modules/mime-db": {
"version": "1.54.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/type-is/node_modules/mime-types": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
"license": "MIT",
"dependencies": {
"mime-db": "^1.54.0"
}, },
"engines": { "engines": {
"node": ">= 0.6" "node": ">= 0.6"
@ -5663,6 +5656,15 @@
"browserslist": ">= 4.21.0" "browserslist": ">= 4.21.0"
} }
}, },
"node_modules/utils-merge": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
"license": "MIT",
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/v8-to-istanbul": { "node_modules/v8-to-istanbul": {
"version": "9.3.0", "version": "9.3.0",
"resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
@ -5828,6 +5830,7 @@
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/write-file-atomic": { "node_modules/write-file-atomic": {

@ -24,7 +24,7 @@
"@types/node-fetch": "^2.6.13", "@types/node-fetch": "^2.6.13",
"cookie-parser": "^1.4.7", "cookie-parser": "^1.4.7",
"di-why": "^0.20.0", "di-why": "^0.20.0",
"express": "^5.1.0", "express": "^4.21.2",
"ioredis": "^5.7.0", "ioredis": "^5.7.0",
"jose": "^6.1.0", "jose": "^6.1.0",
"node-fetch": "^3.3.2", "node-fetch": "^3.3.2",
@ -32,7 +32,7 @@
}, },
"devDependencies": { "devDependencies": {
"@types/cookie-parser": "^1.4.9", "@types/cookie-parser": "^1.4.9",
"@types/express": "^5.0.3", "@types/express": "^4.17.21",
"@types/jest": "^30.0.0", "@types/jest": "^30.0.0",
"@types/node": "^18.0.0", "@types/node": "^18.0.0",
"jest": "^30.1.3", "jest": "^30.1.3",

@ -106,3 +106,4 @@ const appConfigMap = function (env: {
export default appConfigMap; export default appConfigMap;
export type SwissoidAppConfigMap = typeof appConfigMap; export type SwissoidAppConfigMap = typeof appConfigMap;
export type SwissoidAppConfig = ReturnType<SwissoidAppConfigMap>;

@ -11,7 +11,7 @@ export { swissoidAuthLoadDict };
export default swissoidAuthLoadDict; export default swissoidAuthLoadDict;
// Individual loaders if needed separately // Individual loaders if needed separately
export { sessionService, cookieManager, oidcStandardRoutes } from './loaders'; export { sessionService, cookieManager, oidcStandardRoutesMiddleware } from './loaders';
// Export utilities // Export utilities
export { swissoidAppConfigMapNamespace } from './utils/swissoidAppConfigMapListAdd'; export { swissoidAppConfigMapNamespace } from './utils/swissoidAppConfigMapListAdd';

@ -3,18 +3,18 @@ import { LoadDict } from 'di-why';
import redisClient from './redisClient'; import redisClient from './redisClient';
import sessionService from './sessionService'; import sessionService from './sessionService';
import cookieManager from './cookieManager'; import cookieManager from './cookieManager';
import oidcStandardRoutes from './oidcStandardRoutes'; import oidcStandardRoutesMiddleware from './oidcStandardRoutesMiddleware';
import appConfigMap from '../config/appConfigMap'; import appConfigMap from '../config/appConfigMap';
import { swissoidAppConfigMapNamespace } from '../utils/swissoidAppConfigMapListAdd'; import { swissoidAppConfigMapNamespace } from '../utils/swissoidAppConfigMapListAdd';
import { addMergeableConfigMap } from 'di-why'; import { addMergeableConfigMap } from 'di-why';
export { redisClient, sessionService, cookieManager, oidcStandardRoutes }; export { redisClient, sessionService, cookieManager, oidcStandardRoutesMiddleware };
const loadDict: LoadDict = { const loadDict: LoadDict = {
redisClient, redisClient,
sessionService, sessionService,
cookieManager, cookieManager,
oidcStandardRoutes, oidcStandardRoutesMiddleware, // Middleware version for graphql-knifey integration
...addMergeableConfigMap(appConfigMap, swissoidAppConfigMapNamespace), ...addMergeableConfigMap(appConfigMap, swissoidAppConfigMapNamespace),
}; };

@ -1,69 +0,0 @@
import { LoadDictElement } from 'di-why/build/src/DiContainer';
import { Express } from 'express';
import { createOidcStandardRoutes } from '../oidc/OIDCStandardRoutes';
const loadDictElement: LoadDictElement<string> = {
factory: ({
app,
logger,
sessionService,
appConfig,
redisClient
}) => {
// Debug log appConfig to see what's available
logger.log('[OIDC_LOADER] AppConfig received:', {
hasCookieDomain: 'cookieDomain' in appConfig,
cookieDomainValue: appConfig.cookieDomain || 'UNDEFINED',
cookieDomainType: typeof appConfig.cookieDomain,
appConfigKeys: Object.keys(appConfig).sort(),
// Log a few other expected keys to verify appConfig structure
hasSwissoidIssuer: 'swissoidIssuer' in appConfig,
swissoidIssuerValue: appConfig.swissoidIssuer || 'UNDEFINED'
});
// Configuration for standard OIDC flow with signed state
const config = {
logger,
sessionService,
redisClient, // Added for JTI replay prevention
// SwissOID configuration
swissoidIssuer: appConfig.swissoidIssuer,
swissoidClientId: appConfig.swissoidClientId,
swissoidClientSecret: appConfig.swissoidClientSecret,
swissoidTokenEndpoint: appConfig.swissoidTokenEndpoint,
swissoidJwksUri: appConfig.swissoidJwksUri,
swissoidAuthorizeEndpoint: appConfig.swissoidAuthorizeEndpoint || `${appConfig.swissoidIssuer}/authorize`,
// RP configuration
rpCallbackUrl: appConfig.rpCallbackUrl,
rpCookieDomain: appConfig.cookieDomain,
rpFrontendUrl: appConfig.rpFrontendUrl,
// Session configuration
sessionCookieName: appConfig.sessionCookieName,
sessionSecret: appConfig.sessionSecret,
// State signing secret (use a dedicated secret or derive from session secret)
stateSigningSecret: appConfig.stateSigningSecret || appConfig.sessionSecret + '-state-signing'
};
const router = createOidcStandardRoutes(config);
// Mount the standard OIDC routes
(app as Express).use(router);
logger.log('Standard OIDC routes mounted - /login, POST /oidc/callback, /auth/status, /auth/userinfo, /auth/logout');
return 'oidcStandardRoutes-loaded';
},
locateDeps: {
app: 'app',
logger: 'logger',
sessionService: 'sessionService',
appConfig: 'appConfig',
redisClient: 'redisClient'
}
};
export default loadDictElement;

@ -0,0 +1,45 @@
import { LoadDictElement } from 'di-why';
import { Express } from 'express';
import { createOidcStandardRoutes } from '../oidc/OIDCStandardRoutes';
import { buildOidcConfig } from './oidcConfigBuilder';
/**
* OIDC Standard Routes as a Middleware Attacher
* Compatible with express-knifey's middleware system
*/
const loadDictElement: LoadDictElement<(path: string | '*') => void> = {
factory: ({
app,
logger,
sessionService,
appConfig,
redisClient
}) => {
// Build configuration using shared builder
const config = {
logger,
sessionService,
...buildOidcConfig(appConfig, redisClient)
};
const router = createOidcStandardRoutes(config);
// Return a MiddlewareAttacher function
// The path parameter is ignored since OIDC routes define their own paths
return (path: string | '*') => {
// Mount the OIDC routes on the Express app
(app as Express).use(router);
logger.log('OIDC Standard Routes mounted via middleware system - /login, POST /oidc/callback, /auth/status, /auth/logout');
};
},
locateDeps: {
app: 'app',
logger: 'logger',
sessionService: 'sessionService',
appConfig: 'appConfig',
redisClient: 'redisClient'
}
};
export default loadDictElement;

@ -0,0 +1,32 @@
import Redis from "ioredis";
import { SwissoidAppConfig } from "../config/appConfigMap";
/**
* Shared configuration builder for OIDC loaders
*/
export function buildOidcConfig(appConfig: SwissoidAppConfig, redisClient: Redis) {
return {
redisClient,
// SwissOID configuration
swissoidIssuer: appConfig.swissoidIssuer,
swissoidClientId: appConfig.swissoidClientId,
swissoidClientSecret: appConfig.swissoidClientSecret,
swissoidTokenEndpoint: appConfig.swissoidTokenEndpoint,
swissoidJwksUri: appConfig.swissoidJwksUri,
swissoidAuthorizeEndpoint: appConfig.swissoidAuthorizeEndpoint || `${appConfig.swissoidIssuer}/authorize`,
// RP configuration
// These are validated to exist in appConfigMap, but TypeScript can't infer that
rpCallbackUrl: appConfig.rpCallbackUrl!,
rpCookieDomain: appConfig.cookieDomain!,
rpFrontendUrl: appConfig.rpFrontendUrl,
// Session configuration
sessionCookieName: appConfig.sessionCookieName,
sessionSecret: appConfig.sessionSecret,
// State signing secret
stateSigningSecret: appConfig.stateSigningSecret || appConfig.sessionSecret + '-state-signing'
};
}
Loading…
Cancel
Save