s3db.js 13.5.1 → 13.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -19
- package/dist/{s3db.cjs.js → s3db.cjs} +29780 -24384
- package/dist/s3db.cjs.map +1 -0
- package/dist/s3db.es.js +24263 -18860
- package/dist/s3db.es.js.map +1 -1
- package/package.json +227 -21
- package/src/concerns/id.js +90 -6
- package/src/concerns/index.js +2 -1
- package/src/concerns/password-hashing.js +150 -0
- package/src/database.class.js +4 -0
- package/src/plugins/api/auth/basic-auth.js +23 -1
- package/src/plugins/api/auth/index.js +49 -3
- package/src/plugins/api/auth/oauth2-auth.js +171 -0
- package/src/plugins/api/auth/oidc-auth.js +789 -0
- package/src/plugins/api/auth/oidc-client.js +462 -0
- package/src/plugins/api/auth/path-auth-matcher.js +284 -0
- package/src/plugins/api/concerns/event-emitter.js +134 -0
- package/src/plugins/api/concerns/failban-manager.js +651 -0
- package/src/plugins/api/concerns/guards-helpers.js +402 -0
- package/src/plugins/api/concerns/metrics-collector.js +346 -0
- package/src/plugins/api/concerns/opengraph-helper.js +116 -0
- package/src/plugins/api/concerns/state-machine.js +288 -0
- package/src/plugins/api/index.js +514 -54
- package/src/plugins/api/middlewares/failban.js +305 -0
- package/src/plugins/api/middlewares/rate-limit.js +301 -0
- package/src/plugins/api/middlewares/request-id.js +74 -0
- package/src/plugins/api/middlewares/security-headers.js +120 -0
- package/src/plugins/api/middlewares/session-tracking.js +194 -0
- package/src/plugins/api/routes/auth-routes.js +23 -3
- package/src/plugins/api/routes/resource-routes.js +71 -29
- package/src/plugins/api/server.js +1017 -94
- package/src/plugins/api/utils/guards.js +213 -0
- package/src/plugins/api/utils/mime-types.js +154 -0
- package/src/plugins/api/utils/openapi-generator.js +44 -11
- package/src/plugins/api/utils/path-matcher.js +173 -0
- package/src/plugins/api/utils/static-filesystem.js +262 -0
- package/src/plugins/api/utils/static-s3.js +231 -0
- package/src/plugins/api/utils/template-engine.js +262 -0
- package/src/plugins/cloud-inventory/drivers/alibaba-driver.js +853 -0
- package/src/plugins/cloud-inventory/drivers/aws-driver.js +2554 -0
- package/src/plugins/cloud-inventory/drivers/azure-driver.js +637 -0
- package/src/plugins/cloud-inventory/drivers/base-driver.js +99 -0
- package/src/plugins/cloud-inventory/drivers/cloudflare-driver.js +620 -0
- package/src/plugins/cloud-inventory/drivers/digitalocean-driver.js +698 -0
- package/src/plugins/cloud-inventory/drivers/gcp-driver.js +645 -0
- package/src/plugins/cloud-inventory/drivers/hetzner-driver.js +559 -0
- package/src/plugins/cloud-inventory/drivers/linode-driver.js +614 -0
- package/src/plugins/cloud-inventory/drivers/mock-drivers.js +449 -0
- package/src/plugins/cloud-inventory/drivers/mongodb-atlas-driver.js +771 -0
- package/src/plugins/cloud-inventory/drivers/oracle-driver.js +768 -0
- package/src/plugins/cloud-inventory/drivers/vultr-driver.js +636 -0
- package/src/plugins/cloud-inventory/index.js +20 -0
- package/src/plugins/cloud-inventory/registry.js +146 -0
- package/src/plugins/cloud-inventory/terraform-exporter.js +362 -0
- package/src/plugins/cloud-inventory.plugin.js +1333 -0
- package/src/plugins/concerns/plugin-dependencies.js +61 -1
- package/src/plugins/eventual-consistency/analytics.js +1 -0
- package/src/plugins/identity/README.md +335 -0
- package/src/plugins/identity/concerns/mfa-manager.js +204 -0
- package/src/plugins/identity/concerns/password.js +138 -0
- package/src/plugins/identity/concerns/resource-schemas.js +273 -0
- package/src/plugins/identity/concerns/token-generator.js +172 -0
- package/src/plugins/identity/email-service.js +422 -0
- package/src/plugins/identity/index.js +1052 -0
- package/src/plugins/identity/oauth2-server.js +1033 -0
- package/src/plugins/identity/oidc-discovery.js +285 -0
- package/src/plugins/identity/rsa-keys.js +323 -0
- package/src/plugins/identity/server.js +500 -0
- package/src/plugins/identity/session-manager.js +453 -0
- package/src/plugins/identity/ui/layouts/base.js +251 -0
- package/src/plugins/identity/ui/middleware.js +135 -0
- package/src/plugins/identity/ui/pages/admin/client-form.js +247 -0
- package/src/plugins/identity/ui/pages/admin/clients.js +179 -0
- package/src/plugins/identity/ui/pages/admin/dashboard.js +181 -0
- package/src/plugins/identity/ui/pages/admin/user-form.js +283 -0
- package/src/plugins/identity/ui/pages/admin/users.js +263 -0
- package/src/plugins/identity/ui/pages/consent.js +262 -0
- package/src/plugins/identity/ui/pages/forgot-password.js +104 -0
- package/src/plugins/identity/ui/pages/login.js +144 -0
- package/src/plugins/identity/ui/pages/mfa-backup-codes.js +180 -0
- package/src/plugins/identity/ui/pages/mfa-enrollment.js +187 -0
- package/src/plugins/identity/ui/pages/mfa-verification.js +178 -0
- package/src/plugins/identity/ui/pages/oauth-error.js +225 -0
- package/src/plugins/identity/ui/pages/profile.js +361 -0
- package/src/plugins/identity/ui/pages/register.js +226 -0
- package/src/plugins/identity/ui/pages/reset-password.js +128 -0
- package/src/plugins/identity/ui/pages/verify-email.js +172 -0
- package/src/plugins/identity/ui/routes.js +2541 -0
- package/src/plugins/identity/ui/styles/main.css +465 -0
- package/src/plugins/index.js +4 -1
- package/src/plugins/ml/base-model.class.js +32 -7
- package/src/plugins/ml/classification-model.class.js +1 -1
- package/src/plugins/ml/timeseries-model.class.js +3 -1
- package/src/plugins/ml.plugin.js +124 -32
- package/src/plugins/shared/error-handler.js +147 -0
- package/src/plugins/shared/index.js +9 -0
- package/src/plugins/shared/middlewares/compression.js +117 -0
- package/src/plugins/shared/middlewares/cors.js +49 -0
- package/src/plugins/shared/middlewares/index.js +11 -0
- package/src/plugins/shared/middlewares/logging.js +54 -0
- package/src/plugins/shared/middlewares/rate-limit.js +73 -0
- package/src/plugins/shared/middlewares/security.js +158 -0
- package/src/plugins/shared/response-formatter.js +264 -0
- package/src/plugins/tfstate/README.md +126 -126
- package/src/resource.class.js +140 -12
- package/src/schema.class.js +30 -1
- package/src/validator.class.js +57 -6
- package/dist/s3db.cjs.js.map +0 -1
|
@@ -0,0 +1,500 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identity Server - Hono-based HTTP server for Identity Provider Plugin
|
|
3
|
+
*
|
|
4
|
+
* Manages OAuth2/OIDC endpoints only (no CRUD routes)
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { errorHandler } from '../shared/error-handler.js';
|
|
8
|
+
import * as formatter from '../shared/response-formatter.js';
|
|
9
|
+
import {
|
|
10
|
+
createCorsMiddleware,
|
|
11
|
+
createSecurityMiddleware,
|
|
12
|
+
createLoggingMiddleware
|
|
13
|
+
} from '../shared/middlewares/index.js';
|
|
14
|
+
import { idGenerator } from '../../concerns/id.js';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Create Express-style response adapter for Hono context
|
|
18
|
+
* Allows OAuth2Server handlers to use res.status().json() API
|
|
19
|
+
* @param {Object} c - Hono context
|
|
20
|
+
* @returns {Object} Express-style response object
|
|
21
|
+
*/
|
|
22
|
+
function createExpressStyleResponse(c) {
|
|
23
|
+
let statusCode = 200;
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
status(code) {
|
|
27
|
+
statusCode = code;
|
|
28
|
+
return this;
|
|
29
|
+
},
|
|
30
|
+
json(data) {
|
|
31
|
+
return c.json(data, statusCode);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Identity Server class
|
|
38
|
+
* @class
|
|
39
|
+
*/
|
|
40
|
+
export class IdentityServer {
|
|
41
|
+
/**
|
|
42
|
+
* Create Identity server
|
|
43
|
+
* @param {Object} options - Server options
|
|
44
|
+
*/
|
|
45
|
+
constructor(options = {}) {
|
|
46
|
+
this.options = {
|
|
47
|
+
port: options.port || 4000,
|
|
48
|
+
host: options.host || '0.0.0.0',
|
|
49
|
+
verbose: options.verbose || false,
|
|
50
|
+
issuer: options.issuer,
|
|
51
|
+
oauth2Server: options.oauth2Server,
|
|
52
|
+
sessionManager: options.sessionManager || null,
|
|
53
|
+
usersResource: options.usersResource || null,
|
|
54
|
+
identityPlugin: options.identityPlugin || null,
|
|
55
|
+
failbanManager: options.failbanManager || null,
|
|
56
|
+
failbanConfig: options.failbanConfig || {},
|
|
57
|
+
cors: options.cors || {},
|
|
58
|
+
security: options.security || {},
|
|
59
|
+
logging: options.logging || {}
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
this.app = null;
|
|
63
|
+
this.server = null;
|
|
64
|
+
this.isRunning = false;
|
|
65
|
+
this.initialized = false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Setup failban middleware for brute force protection
|
|
70
|
+
* @private
|
|
71
|
+
*/
|
|
72
|
+
_setupFailbanMiddleware() {
|
|
73
|
+
const { failbanManager } = this.options;
|
|
74
|
+
|
|
75
|
+
// Global ban check middleware
|
|
76
|
+
this.app.use('*', async (c, next) => {
|
|
77
|
+
// Extract IP address
|
|
78
|
+
const ip = c.req.header('x-forwarded-for')?.split(',')[0]?.trim() ||
|
|
79
|
+
c.req.header('x-real-ip') ||
|
|
80
|
+
c.env?.ip ||
|
|
81
|
+
'unknown';
|
|
82
|
+
|
|
83
|
+
// Store IP in context for later use
|
|
84
|
+
c.set('clientIp', ip);
|
|
85
|
+
|
|
86
|
+
// Check if blacklisted
|
|
87
|
+
if (failbanManager.isBlacklisted(ip)) {
|
|
88
|
+
c.header('X-Ban-Status', 'blacklisted');
|
|
89
|
+
c.header('X-Ban-Reason', 'IP is permanently blacklisted');
|
|
90
|
+
|
|
91
|
+
if (this.options.verbose) {
|
|
92
|
+
console.log(`[Failban] Blocked blacklisted IP: ${ip}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return c.json({
|
|
96
|
+
error: 'Forbidden',
|
|
97
|
+
message: 'Your IP address has been permanently blocked',
|
|
98
|
+
ip
|
|
99
|
+
}, 403);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Check country restrictions (GeoIP)
|
|
103
|
+
if (this.options.failbanConfig.geo?.enabled) {
|
|
104
|
+
const countryBlock = failbanManager.checkCountryBlock(ip);
|
|
105
|
+
if (countryBlock) {
|
|
106
|
+
c.header('X-Ban-Status', 'country_blocked');
|
|
107
|
+
c.header('X-Ban-Reason', countryBlock.reason);
|
|
108
|
+
c.header('X-Country-Code', countryBlock.country);
|
|
109
|
+
|
|
110
|
+
if (this.options.verbose) {
|
|
111
|
+
console.log(`[Failban] Blocked country ${countryBlock.country} for IP: ${ip}`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return c.json({
|
|
115
|
+
error: 'Forbidden',
|
|
116
|
+
message: 'Access from your country is not allowed',
|
|
117
|
+
country: countryBlock.country,
|
|
118
|
+
ip
|
|
119
|
+
}, 403);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Check if banned
|
|
124
|
+
if (failbanManager.isBanned(ip)) {
|
|
125
|
+
const ban = await failbanManager.getBan(ip);
|
|
126
|
+
|
|
127
|
+
if (ban) {
|
|
128
|
+
const expiresAt = new Date(ban.expiresAt);
|
|
129
|
+
const retryAfter = Math.ceil((expiresAt.getTime() - Date.now()) / 1000);
|
|
130
|
+
|
|
131
|
+
c.header('Retry-After', String(retryAfter));
|
|
132
|
+
c.header('X-Ban-Status', 'banned');
|
|
133
|
+
c.header('X-Ban-Reason', ban.reason);
|
|
134
|
+
c.header('X-Ban-Expires', ban.expiresAt);
|
|
135
|
+
|
|
136
|
+
if (this.options.verbose) {
|
|
137
|
+
console.log(`[Failban] Blocked banned IP: ${ip} (expires in ${retryAfter}s)`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return c.json({
|
|
141
|
+
error: 'Forbidden',
|
|
142
|
+
message: 'Your IP address has been temporarily banned due to security violations',
|
|
143
|
+
reason: ban.reason,
|
|
144
|
+
expiresAt: ban.expiresAt,
|
|
145
|
+
retryAfter
|
|
146
|
+
}, 403);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Not banned - continue
|
|
151
|
+
await next();
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
if (this.options.verbose) {
|
|
155
|
+
console.log('[Identity Server] Failban middleware enabled (global ban check)');
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Setup all routes
|
|
161
|
+
* @private
|
|
162
|
+
*/
|
|
163
|
+
_setupRoutes() {
|
|
164
|
+
// Request ID middleware
|
|
165
|
+
this.app.use('*', async (c, next) => {
|
|
166
|
+
c.set('requestId', idGenerator());
|
|
167
|
+
c.set('verbose', this.options.verbose);
|
|
168
|
+
await next();
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Apply CORS middleware if enabled
|
|
172
|
+
if (this.options.cors.enabled) {
|
|
173
|
+
const corsMiddleware = createCorsMiddleware(this.options.cors);
|
|
174
|
+
this.app.use('*', corsMiddleware);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Apply security headers if enabled
|
|
178
|
+
if (this.options.security.enabled) {
|
|
179
|
+
const securityMiddleware = createSecurityMiddleware(this.options.security);
|
|
180
|
+
this.app.use('*', securityMiddleware);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Apply failban middleware if enabled (global IP ban check)
|
|
184
|
+
if (this.options.failbanManager && this.options.failbanConfig.enabled) {
|
|
185
|
+
this._setupFailbanMiddleware();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Apply logging middleware if enabled
|
|
189
|
+
if (this.options.logging.enabled) {
|
|
190
|
+
const loggingMiddleware = createLoggingMiddleware(this.options.logging);
|
|
191
|
+
this.app.use('*', loggingMiddleware);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Health check endpoints
|
|
195
|
+
this.app.get('/health', (c) => {
|
|
196
|
+
const response = formatter.success({
|
|
197
|
+
status: 'ok',
|
|
198
|
+
service: 'identity-provider',
|
|
199
|
+
uptime: process.uptime(),
|
|
200
|
+
timestamp: new Date().toISOString()
|
|
201
|
+
});
|
|
202
|
+
return c.json(response);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
this.app.get('/health/live', (c) => {
|
|
206
|
+
const response = formatter.success({
|
|
207
|
+
status: 'alive',
|
|
208
|
+
timestamp: new Date().toISOString()
|
|
209
|
+
});
|
|
210
|
+
return c.json(response);
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
this.app.get('/health/ready', (c) => {
|
|
214
|
+
const isReady = this.options.oauth2Server !== null;
|
|
215
|
+
|
|
216
|
+
if (!isReady) {
|
|
217
|
+
const response = formatter.error('Service not ready', {
|
|
218
|
+
status: 503,
|
|
219
|
+
code: 'NOT_READY'
|
|
220
|
+
});
|
|
221
|
+
return c.json(response, 503);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const response = formatter.success({
|
|
225
|
+
status: 'ready',
|
|
226
|
+
timestamp: new Date().toISOString()
|
|
227
|
+
});
|
|
228
|
+
return c.json(response);
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// Root endpoint - discovery redirect
|
|
232
|
+
this.app.get('/', (c) => {
|
|
233
|
+
return c.redirect('/.well-known/openid-configuration', 302);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
// Setup OAuth2/OIDC routes
|
|
237
|
+
this._setupOAuth2Routes();
|
|
238
|
+
|
|
239
|
+
// Setup UI routes (login, register, profile, etc.)
|
|
240
|
+
this._setupUIRoutes();
|
|
241
|
+
|
|
242
|
+
// Global error handler
|
|
243
|
+
this.app.onError((err, c) => {
|
|
244
|
+
return errorHandler(err, c);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// 404 handler
|
|
248
|
+
this.app.notFound((c) => {
|
|
249
|
+
const response = formatter.error('Route not found', {
|
|
250
|
+
status: 404,
|
|
251
|
+
code: 'NOT_FOUND',
|
|
252
|
+
details: {
|
|
253
|
+
path: c.req.path,
|
|
254
|
+
method: c.req.method
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
return c.json(response, 404);
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Setup OAuth2/OIDC routes
|
|
263
|
+
* @private
|
|
264
|
+
*/
|
|
265
|
+
_setupOAuth2Routes() {
|
|
266
|
+
const { oauth2Server } = this.options;
|
|
267
|
+
|
|
268
|
+
if (!oauth2Server) {
|
|
269
|
+
console.error('[Identity Server] OAuth2 Server not provided');
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// OIDC Discovery endpoint
|
|
274
|
+
this.app.get('/.well-known/openid-configuration', async (c) => {
|
|
275
|
+
const res = createExpressStyleResponse(c);
|
|
276
|
+
return await oauth2Server.discoveryHandler(c.req, res);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
// JWKS (JSON Web Key Set) endpoint
|
|
280
|
+
this.app.get('/.well-known/jwks.json', async (c) => {
|
|
281
|
+
const res = createExpressStyleResponse(c);
|
|
282
|
+
return await oauth2Server.jwksHandler(c.req, res);
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
// OAuth2 Token endpoint
|
|
286
|
+
this.app.post('/oauth/token', async (c) => {
|
|
287
|
+
const res = createExpressStyleResponse(c);
|
|
288
|
+
return await oauth2Server.tokenHandler(c.req, res);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
// OIDC UserInfo endpoint
|
|
292
|
+
this.app.get('/oauth/userinfo', async (c) => {
|
|
293
|
+
const res = createExpressStyleResponse(c);
|
|
294
|
+
return await oauth2Server.userinfoHandler(c.req, res);
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
// Token introspection endpoint
|
|
298
|
+
this.app.post('/oauth/introspect', async (c) => {
|
|
299
|
+
const res = createExpressStyleResponse(c);
|
|
300
|
+
return await oauth2Server.introspectHandler(c.req, res);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// Authorization endpoint (GET for user consent UI)
|
|
304
|
+
this.app.get('/oauth/authorize', async (c) => {
|
|
305
|
+
const res = createExpressStyleResponse(c);
|
|
306
|
+
return await oauth2Server.authorizeHandler(c.req, res);
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
// Authorization endpoint (POST for processing login)
|
|
310
|
+
this.app.post('/oauth/authorize', async (c) => {
|
|
311
|
+
const res = createExpressStyleResponse(c);
|
|
312
|
+
return await oauth2Server.authorizePostHandler(c.req, res);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
// Client registration endpoint
|
|
316
|
+
this.app.post('/oauth/register', async (c) => {
|
|
317
|
+
const res = createExpressStyleResponse(c);
|
|
318
|
+
return await oauth2Server.registerClientHandler(c.req, res);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
// Token revocation endpoint
|
|
322
|
+
this.app.post('/oauth/revoke', async (c) => {
|
|
323
|
+
const res = createExpressStyleResponse(c);
|
|
324
|
+
return await oauth2Server.revokeHandler(c.req, res);
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
if (this.options.verbose) {
|
|
328
|
+
console.log('[Identity Server] Mounted OAuth2/OIDC routes:');
|
|
329
|
+
console.log('[Identity Server] GET /.well-known/openid-configuration (OIDC Discovery)');
|
|
330
|
+
console.log('[Identity Server] GET /.well-known/jwks.json (JWKS)');
|
|
331
|
+
console.log('[Identity Server] GET /oauth/authorize (Authorization UI)');
|
|
332
|
+
console.log('[Identity Server] POST /oauth/authorize (Process Login)');
|
|
333
|
+
console.log('[Identity Server] POST /oauth/token (Token)');
|
|
334
|
+
console.log('[Identity Server] GET /oauth/userinfo (UserInfo)');
|
|
335
|
+
console.log('[Identity Server] POST /oauth/introspect (Introspection)');
|
|
336
|
+
console.log('[Identity Server] POST /oauth/register (Client Registration)');
|
|
337
|
+
console.log('[Identity Server] POST /oauth/revoke (Token Revocation)');
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Setup UI routes (login, register, profile, etc.)
|
|
343
|
+
* @private
|
|
344
|
+
*/
|
|
345
|
+
async _setupUIRoutes() {
|
|
346
|
+
const { sessionManager, identityPlugin } = this.options;
|
|
347
|
+
|
|
348
|
+
if (!sessionManager || !identityPlugin) {
|
|
349
|
+
if (this.options.verbose) {
|
|
350
|
+
console.log('[Identity Server] SessionManager or IdentityPlugin not provided, skipping UI routes');
|
|
351
|
+
}
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
try {
|
|
356
|
+
// Dynamic import of UI routes
|
|
357
|
+
const { registerUIRoutes } = await import('./ui/routes.js');
|
|
358
|
+
|
|
359
|
+
// Register all UI routes (login, register, logout)
|
|
360
|
+
registerUIRoutes(this.app, identityPlugin);
|
|
361
|
+
|
|
362
|
+
if (this.options.verbose) {
|
|
363
|
+
console.log('[Identity Server] Mounted UI routes:');
|
|
364
|
+
console.log('[Identity Server] GET /login (Login Form)');
|
|
365
|
+
console.log('[Identity Server] POST /login (Process Login)');
|
|
366
|
+
console.log('[Identity Server] GET /register (Registration Form)');
|
|
367
|
+
console.log('[Identity Server] POST /register (Process Registration)');
|
|
368
|
+
console.log('[Identity Server] GET /logout (Logout)');
|
|
369
|
+
console.log('[Identity Server] POST /logout (Logout)');
|
|
370
|
+
console.log('[Identity Server] GET /forgot-password (Forgot Password Form)');
|
|
371
|
+
console.log('[Identity Server] POST /forgot-password (Process Forgot Password)');
|
|
372
|
+
console.log('[Identity Server] GET /reset-password (Reset Password Form)');
|
|
373
|
+
console.log('[Identity Server] POST /reset-password (Process Password Reset)');
|
|
374
|
+
console.log('[Identity Server] GET /profile (User Profile - Protected)');
|
|
375
|
+
console.log('[Identity Server] POST /profile/update (Update Profile)');
|
|
376
|
+
console.log('[Identity Server] POST /profile/change-password (Change Password)');
|
|
377
|
+
console.log('[Identity Server] POST /profile/logout-session (Logout Specific Session)');
|
|
378
|
+
console.log('[Identity Server] POST /profile/logout-all-sessions (Logout All Other Sessions)');
|
|
379
|
+
console.log('[Identity Server] GET /admin (Admin Dashboard - Protected)');
|
|
380
|
+
console.log('[Identity Server] GET /admin/clients (List OAuth2 Clients)');
|
|
381
|
+
console.log('[Identity Server] GET /admin/clients/new (New Client Form)');
|
|
382
|
+
console.log('[Identity Server] POST /admin/clients/create (Create Client)');
|
|
383
|
+
console.log('[Identity Server] GET /admin/clients/:id/edit (Edit Client Form)');
|
|
384
|
+
console.log('[Identity Server] POST /admin/clients/:id/update (Update Client)');
|
|
385
|
+
console.log('[Identity Server] POST /admin/clients/:id/delete (Delete Client)');
|
|
386
|
+
console.log('[Identity Server] POST /admin/clients/:id/rotate-secret (Rotate Client Secret)');
|
|
387
|
+
console.log('[Identity Server] POST /admin/clients/:id/toggle-active (Toggle Client Active)');
|
|
388
|
+
console.log('[Identity Server] GET /admin/users (List Users - Protected)');
|
|
389
|
+
console.log('[Identity Server] GET /admin/users/:id/edit (Edit User Form)');
|
|
390
|
+
console.log('[Identity Server] POST /admin/users/:id/update (Update User)');
|
|
391
|
+
console.log('[Identity Server] POST /admin/users/:id/delete (Delete User)');
|
|
392
|
+
console.log('[Identity Server] POST /admin/users/:id/change-status (Change User Status)');
|
|
393
|
+
console.log('[Identity Server] POST /admin/users/:id/verify-email (Mark Email Verified)');
|
|
394
|
+
console.log('[Identity Server] POST /admin/users/:id/reset-password (Send Password Reset)');
|
|
395
|
+
console.log('[Identity Server] POST /admin/users/:id/toggle-admin (Toggle Admin Role)');
|
|
396
|
+
console.log('[Identity Server] GET /oauth/authorize (OAuth2 Consent Screen - Overrides OAuth2Server)');
|
|
397
|
+
console.log('[Identity Server] POST /oauth/consent (Process OAuth2 Consent Decision)');
|
|
398
|
+
console.log('[Identity Server] GET /verify-email (Verify Email with Token)');
|
|
399
|
+
console.log('[Identity Server] POST /verify-email/resend (Resend Verification Email)');
|
|
400
|
+
}
|
|
401
|
+
} catch (error) {
|
|
402
|
+
console.error('[Identity Server] Failed to setup UI routes:', error);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Start the server
|
|
408
|
+
* @returns {Promise<void>}
|
|
409
|
+
*/
|
|
410
|
+
async start() {
|
|
411
|
+
if (this.isRunning) {
|
|
412
|
+
console.warn('[Identity Server] Server is already running');
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Dynamic import of Hono dependencies
|
|
417
|
+
if (!this.initialized) {
|
|
418
|
+
const { Hono } = await import('hono');
|
|
419
|
+
const { serve } = await import('@hono/node-server');
|
|
420
|
+
|
|
421
|
+
this.Hono = Hono;
|
|
422
|
+
this.serve = serve;
|
|
423
|
+
|
|
424
|
+
// Initialize app
|
|
425
|
+
this.app = new Hono();
|
|
426
|
+
|
|
427
|
+
// Setup routes
|
|
428
|
+
this._setupRoutes();
|
|
429
|
+
|
|
430
|
+
this.initialized = true;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
const { port, host } = this.options;
|
|
434
|
+
|
|
435
|
+
return new Promise((resolve, reject) => {
|
|
436
|
+
try {
|
|
437
|
+
this.server = this.serve({
|
|
438
|
+
fetch: this.app.fetch,
|
|
439
|
+
port,
|
|
440
|
+
hostname: host
|
|
441
|
+
}, (info) => {
|
|
442
|
+
this.isRunning = true;
|
|
443
|
+
console.log(`[Identity Server] Server listening on http://${info.address}:${info.port}`);
|
|
444
|
+
console.log(`[Identity Server] Issuer: ${this.options.issuer}`);
|
|
445
|
+
console.log(`[Identity Server] Discovery: ${this.options.issuer}/.well-known/openid-configuration`);
|
|
446
|
+
resolve();
|
|
447
|
+
});
|
|
448
|
+
} catch (err) {
|
|
449
|
+
reject(err);
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Stop the server
|
|
456
|
+
* @returns {Promise<void>}
|
|
457
|
+
*/
|
|
458
|
+
async stop() {
|
|
459
|
+
if (!this.isRunning) {
|
|
460
|
+
console.warn('[Identity Server] Server is not running');
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
if (this.server && typeof this.server.close === 'function') {
|
|
465
|
+
await new Promise((resolve) => {
|
|
466
|
+
this.server.close(() => {
|
|
467
|
+
this.isRunning = false;
|
|
468
|
+
console.log('[Identity Server] Server stopped');
|
|
469
|
+
resolve();
|
|
470
|
+
});
|
|
471
|
+
});
|
|
472
|
+
} else {
|
|
473
|
+
this.isRunning = false;
|
|
474
|
+
console.log('[Identity Server] Server stopped');
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
/**
|
|
479
|
+
* Get server info
|
|
480
|
+
* @returns {Object} Server information
|
|
481
|
+
*/
|
|
482
|
+
getInfo() {
|
|
483
|
+
return {
|
|
484
|
+
isRunning: this.isRunning,
|
|
485
|
+
port: this.options.port,
|
|
486
|
+
host: this.options.host,
|
|
487
|
+
issuer: this.options.issuer
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* Get Hono app instance
|
|
493
|
+
* @returns {Hono} Hono app
|
|
494
|
+
*/
|
|
495
|
+
getApp() {
|
|
496
|
+
return this.app;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
export default IdentityServer;
|