@nik2208/node-auth 1.1.0 → 1.1.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.
Files changed (51) hide show
  1. package/dist/index.d.ts +8 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +3 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/interfaces/roles-permissions-store.interface.d.ts +82 -0
  6. package/dist/interfaces/roles-permissions-store.interface.d.ts.map +1 -0
  7. package/dist/interfaces/roles-permissions-store.interface.js +3 -0
  8. package/dist/interfaces/roles-permissions-store.interface.js.map +1 -0
  9. package/dist/interfaces/session-store.interface.d.ts +82 -0
  10. package/dist/interfaces/session-store.interface.d.ts.map +1 -0
  11. package/dist/interfaces/session-store.interface.js +3 -0
  12. package/dist/interfaces/session-store.interface.js.map +1 -0
  13. package/dist/interfaces/tenant-store.interface.d.ts +97 -0
  14. package/dist/interfaces/tenant-store.interface.d.ts.map +1 -0
  15. package/dist/interfaces/tenant-store.interface.js +3 -0
  16. package/dist/interfaces/tenant-store.interface.js.map +1 -0
  17. package/dist/interfaces/user-metadata-store.interface.d.ts +50 -0
  18. package/dist/interfaces/user-metadata-store.interface.d.ts.map +1 -0
  19. package/dist/interfaces/user-metadata-store.interface.js +3 -0
  20. package/dist/interfaces/user-metadata-store.interface.js.map +1 -0
  21. package/dist/interfaces/user-store.interface.d.ts +41 -0
  22. package/dist/interfaces/user-store.interface.d.ts.map +1 -1
  23. package/dist/models/auth-config.model.d.ts +29 -0
  24. package/dist/models/auth-config.model.d.ts.map +1 -1
  25. package/dist/models/session.model.d.ts +28 -0
  26. package/dist/models/session.model.d.ts.map +1 -0
  27. package/dist/models/session.model.js +3 -0
  28. package/dist/models/session.model.js.map +1 -0
  29. package/dist/models/tenant.model.d.ts +20 -0
  30. package/dist/models/tenant.model.d.ts.map +1 -0
  31. package/dist/models/tenant.model.js +3 -0
  32. package/dist/models/tenant.model.js.map +1 -0
  33. package/dist/models/token.model.d.ts +2 -0
  34. package/dist/models/token.model.d.ts.map +1 -1
  35. package/dist/models/user.model.d.ts +12 -0
  36. package/dist/models/user.model.d.ts.map +1 -1
  37. package/dist/router/admin.router.d.ts +21 -0
  38. package/dist/router/admin.router.d.ts.map +1 -0
  39. package/dist/router/admin.router.js +627 -0
  40. package/dist/router/admin.router.js.map +1 -0
  41. package/dist/router/auth.router.d.ts.map +1 -1
  42. package/dist/router/auth.router.js +180 -8
  43. package/dist/router/auth.router.js.map +1 -1
  44. package/dist/services/mailer.service.d.ts +2 -0
  45. package/dist/services/mailer.service.d.ts.map +1 -1
  46. package/dist/services/mailer.service.js +46 -0
  47. package/dist/services/mailer.service.js.map +1 -1
  48. package/dist/services/token.service.d.ts.map +1 -1
  49. package/dist/services/token.service.js +4 -3
  50. package/dist/services/token.service.js.map +1 -1
  51. package/package.json +1 -1
@@ -0,0 +1,627 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createAdminRouter = createAdminRouter;
4
+ const express_1 = require("express");
5
+ function adminAuth(secret) {
6
+ return (req, res, next) => {
7
+ const auth = req.headers.authorization;
8
+ if (!auth || !auth.startsWith('Bearer ')) {
9
+ res.status(401).json({ error: 'Unauthorized' });
10
+ return;
11
+ }
12
+ const token = auth.slice(7);
13
+ if (token !== secret) {
14
+ res.status(403).json({ error: 'Forbidden' });
15
+ return;
16
+ }
17
+ next();
18
+ };
19
+ }
20
+ // ---------------------------------------------------------------------------
21
+ // Embedded HTML/JS/CSS admin UI (no build step, no external dependencies)
22
+ // ---------------------------------------------------------------------------
23
+ function buildAdminHtml(baseUrl, features) {
24
+ const tabs = [
25
+ { id: 'users', label: '👤 Users' },
26
+ ...(features.sessions ? [{ id: 'sessions', label: '📋 Sessions' }] : []),
27
+ ...(features.roles ? [{ id: 'roles', label: '🛡️ Roles & Permissions' }] : []),
28
+ ...(features.tenants ? [{ id: 'tenants', label: '🏢 Tenants' }] : []),
29
+ ];
30
+ return `<!DOCTYPE html>
31
+ <html lang="en">
32
+ <head>
33
+ <meta charset="UTF-8">
34
+ <meta name="viewport" content="width=device-width,initial-scale=1">
35
+ <title>node-auth Admin</title>
36
+ <style>
37
+ *{box-sizing:border-box;margin:0;padding:0}
38
+ body{font-family:system-ui,-apple-system,sans-serif;background:#f0f2f5;color:#1a1a2e}
39
+ /* Login */
40
+ #login{display:flex;align-items:center;justify-content:center;min-height:100vh}
41
+ .login-card{background:white;padding:2.5rem;border-radius:12px;box-shadow:0 4px 24px rgba(0,0,0,.12);width:340px}
42
+ .login-card h1{font-size:1.5rem;margin-bottom:.25rem}
43
+ .login-card p{color:#666;font-size:.875rem;margin-bottom:1.5rem}
44
+ /* App */
45
+ #app{display:none;min-height:100vh;flex-direction:column}
46
+ header{background:#1a1a2e;color:white;padding:1rem 2rem;display:flex;align-items:center;justify-content:space-between}
47
+ header h1{font-size:1.1rem;font-weight:700;letter-spacing:.5px}
48
+ header span{font-size:.75rem;opacity:.6}
49
+ nav{background:white;border-bottom:1px solid #e5e7eb;padding:0 2rem;display:flex;gap:.25rem}
50
+ nav button{padding:.75rem 1.25rem;border:none;background:none;cursor:pointer;border-bottom:3px solid transparent;color:#6b7280;font-size:.875rem;font-weight:500;transition:all .15s}
51
+ nav button:hover{color:#1a1a2e}
52
+ nav button.active{color:#1a1a2e;border-color:#1a1a2e}
53
+ main{padding:2rem;flex:1}
54
+ /* Cards */
55
+ .card{background:white;border-radius:10px;box-shadow:0 1px 4px rgba(0,0,0,.08);overflow:hidden;margin-bottom:1.5rem}
56
+ .card-header{padding:1rem 1.5rem;border-bottom:1px solid #f3f4f6;display:flex;align-items:center;justify-content:space-between}
57
+ .card-header h2{font-size:.9375rem;font-weight:600}
58
+ .card-header .meta{font-size:.75rem;color:#9ca3af}
59
+ /* Tables */
60
+ .table-wrap{overflow-x:auto}
61
+ table{width:100%;border-collapse:collapse}
62
+ th{padding:.625rem 1rem;text-align:left;font-size:.6875rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:#9ca3af;background:#fafafa;border-bottom:1px solid #f3f4f6;white-space:nowrap}
63
+ td{padding:.75rem 1rem;border-bottom:1px solid #f9fafb;font-size:.8125rem;max-width:240px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
64
+ tr:last-child td{border-bottom:none}
65
+ tr:hover td{background:#fafafa}
66
+ /* Badges */
67
+ .badge{display:inline-flex;align-items:center;gap:.25rem;padding:.125rem .5rem;border-radius:999px;font-size:.6875rem;font-weight:600}
68
+ .badge-green{background:#dcfce7;color:#166534}
69
+ .badge-gray{background:#f3f4f6;color:#4b5563}
70
+ .badge-red{background:#fee2e2;color:#991b1b}
71
+ .badge-blue{background:#dbeafe;color:#1d4ed8}
72
+ /* Forms */
73
+ .form-row{display:flex;gap:.5rem;align-items:center}
74
+ input[type=text],input[type=password],input[type=email]{padding:.5rem .75rem;border:1px solid #d1d5db;border-radius:6px;font-size:.875rem;width:100%;outline:none;transition:border .15s}
75
+ input:focus{border-color:#1a1a2e}
76
+ .btn{padding:.5rem 1rem;border:none;border-radius:6px;font-size:.875rem;font-weight:500;cursor:pointer;transition:opacity .15s}
77
+ .btn:hover{opacity:.88}
78
+ .btn-primary{background:#1a1a2e;color:white}
79
+ .btn-danger{background:#dc2626;color:white;font-size:.75rem;padding:.25rem .6rem}
80
+ .btn-sm{font-size:.75rem;padding:.25rem .6rem}
81
+ /* Misc */
82
+ .empty{text-align:center;color:#9ca3af;padding:3rem 1rem}
83
+ .empty svg{display:block;margin:0 auto 1rem;opacity:.4}
84
+ .pager{display:flex;align-items:center;gap:.5rem;padding:.75rem 1rem;border-top:1px solid #f3f4f6;font-size:.8125rem;color:#6b7280}
85
+ .pager button{padding:.25rem .625rem;border:1px solid #d1d5db;border-radius:4px;background:white;cursor:pointer;font-size:.8125rem}
86
+ .pager button:disabled{opacity:.4;cursor:default}
87
+ .alert{padding:.75rem 1rem;border-radius:6px;font-size:.8125rem;margin-bottom:1rem}
88
+ .alert-error{background:#fee2e2;color:#991b1b}
89
+ .alert-success{background:#dcfce7;color:#166534}
90
+ .spinner{display:inline-block;width:16px;height:16px;border:2px solid #e5e7eb;border-top-color:#1a1a2e;border-radius:50%;animation:spin .6s linear infinite;vertical-align:middle}
91
+ @keyframes spin{to{transform:rotate(360deg)}}
92
+ #flash{position:fixed;top:1rem;right:1rem;z-index:999;max-width:320px}
93
+ </style>
94
+ </head>
95
+ <body>
96
+
97
+ <!-- Login screen -->
98
+ <div id="login">
99
+ <div class="login-card">
100
+ <h1>🔐 node-auth</h1>
101
+ <p>Administration panel</p>
102
+ <div id="login-error" class="alert alert-error" style="display:none"></div>
103
+ <div style="display:flex;flex-direction:column;gap:.75rem">
104
+ <input type="password" id="secret-input" placeholder="Admin secret" autofocus>
105
+ <button class="btn btn-primary" onclick="doLogin()">Sign in</button>
106
+ </div>
107
+ </div>
108
+ </div>
109
+
110
+ <!-- Main app -->
111
+ <div id="app" style="display:flex">
112
+ <div id="flash"></div>
113
+ <header>
114
+ <h1>🔐 node-auth Admin</h1>
115
+ <span id="header-meta"></span>
116
+ </header>
117
+ <nav id="nav">
118
+ ${tabs.map(t => `<button id="tab-${t.id}" onclick="showTab('${t.id}')">${t.label}</button>`).join('\n ')}
119
+ <button class="btn" style="margin-left:auto;margin-top:.4rem;margin-bottom:.4rem;font-size:.75rem;padding:.25rem .75rem;background:#f3f4f6;border:1px solid #e5e7eb;border-radius:6px" onclick="doLogout()">Logout</button>
120
+ </nav>
121
+ <main id="main"></main>
122
+ </div>
123
+
124
+ <script>
125
+ const BASE = '${baseUrl}';
126
+ let _token = '';
127
+ let _state = { tab: 'users', users: { page: 0 }, sessions: { page: 0 }, roles: {}, tenants: {} };
128
+ const PAGE_SIZE = 20;
129
+
130
+ // ---- Auth ----------------------------------------------------------------
131
+ function doLogin() {
132
+ const val = document.getElementById('secret-input').value.trim();
133
+ if (!val) return;
134
+ sessionStorage.setItem('admin_token', val);
135
+ _token = val;
136
+ document.getElementById('login-error').style.display = 'none';
137
+ api('GET', '/admin/api/ping').then(() => {
138
+ document.getElementById('login').style.display = 'none';
139
+ document.getElementById('app').style.display = 'flex';
140
+ document.getElementById('app').style.flexDirection = 'column';
141
+ showTab('users');
142
+ }).catch(() => {
143
+ sessionStorage.removeItem('admin_token');
144
+ _token = '';
145
+ document.getElementById('login-error').textContent = 'Invalid admin secret';
146
+ document.getElementById('login-error').style.display = 'block';
147
+ });
148
+ }
149
+ function doLogout() {
150
+ sessionStorage.removeItem('admin_token');
151
+ location.reload();
152
+ }
153
+ document.getElementById('secret-input').addEventListener('keydown', e => { if (e.key === 'Enter') doLogin(); });
154
+ // Auto-login if token stored
155
+ const stored = sessionStorage.getItem('admin_token');
156
+ if (stored) { _token = stored; api('GET', '/admin/api/ping').then(() => {
157
+ document.getElementById('login').style.display = 'none';
158
+ document.getElementById('app').style.display = 'flex';
159
+ document.getElementById('app').style.flexDirection = 'column';
160
+ showTab('users');
161
+ }).catch(() => { sessionStorage.removeItem('admin_token'); _token = ''; }); }
162
+
163
+ // ---- API helper ----------------------------------------------------------
164
+ async function api(method, path, body) {
165
+ const res = await fetch(BASE + path, {
166
+ method,
167
+ headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + _token },
168
+ body: body ? JSON.stringify(body) : undefined,
169
+ });
170
+ if (!res.ok) {
171
+ const err = await res.json().catch(() => ({ error: res.statusText }));
172
+ throw new Error(err.error || res.statusText);
173
+ }
174
+ return res.json();
175
+ }
176
+
177
+ // ---- Flash ---------------------------------------------------------------
178
+ function flash(msg, type = 'success') {
179
+ const el = document.createElement('div');
180
+ el.className = 'alert alert-' + (type === 'error' ? 'error' : 'success');
181
+ el.textContent = msg;
182
+ el.style.cssText = 'padding:.75rem 1rem;border-radius:6px;font-size:.8125rem;margin-bottom:.5rem;box-shadow:0 2px 8px rgba(0,0,0,.1)';
183
+ document.getElementById('flash').appendChild(el);
184
+ setTimeout(() => el.remove(), 3500);
185
+ }
186
+
187
+ // ---- Tab routing ---------------------------------------------------------
188
+ function showTab(tab) {
189
+ _state.tab = tab;
190
+ document.querySelectorAll('nav button').forEach(b => b.classList.remove('active'));
191
+ const btn = document.getElementById('tab-' + tab);
192
+ if (btn) btn.classList.add('active');
193
+ if (tab === 'users') renderUsers();
194
+ else if (tab === 'sessions') renderSessions();
195
+ else if (tab === 'roles') renderRoles();
196
+ else if (tab === 'tenants') renderTenants();
197
+ }
198
+
199
+ // ---- Helpers -------------------------------------------------------------
200
+ function badge(text, cls) {
201
+ return '<span class="badge badge-' + cls + '">' + esc(String(text)) + '</span>';
202
+ }
203
+ function esc(s) {
204
+ return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
205
+ }
206
+ function ts(d) {
207
+ if (!d) return '—';
208
+ try { return new Date(d).toLocaleString(); } catch { return String(d); }
209
+ }
210
+ function pagerHtml(page, hasMore, prev, next) {
211
+ return '<div class="pager"><button ' + (page === 0 ? 'disabled' : '') + ' onclick="' + prev + '">← Prev</button>'
212
+ + '<span>Page ' + (page + 1) + '</span>'
213
+ + '<button ' + (!hasMore ? 'disabled' : '') + ' onclick="' + next + '">Next →</button></div>';
214
+ }
215
+
216
+ // ---- Users ---------------------------------------------------------------
217
+ async function renderUsers() {
218
+ const main = document.getElementById('main');
219
+ main.innerHTML = '<div class="card"><div class="card-header"><h2>Users</h2><span class="meta"><span class="spinner"></span></span></div></div>';
220
+ try {
221
+ const { users, total } = await api('GET', '/admin/api/users?limit=' + PAGE_SIZE + '&offset=' + (_state.users.page * PAGE_SIZE));
222
+ const hasMore = (_state.users.page + 1) * PAGE_SIZE < total;
223
+ main.innerHTML = \`
224
+ <div class="card">
225
+ <div class="card-header"><h2>Users</h2><span class="meta">\${total} total</span></div>
226
+ <div class="table-wrap">
227
+ <table>
228
+ <thead><tr>
229
+ <th>ID</th><th>Email</th><th>Role</th><th>Verified</th><th>2FA</th><th>Created</th><th></th>
230
+ </tr></thead>
231
+ <tbody>\${users.length === 0 ? '<tr><td colspan="7"><div class="empty">No users found</div></td></tr>' :
232
+ users.map(u => \`<tr>
233
+ <td style="font-family:monospace;font-size:.75rem">\${esc(u.id)}</td>
234
+ <td>\${esc(u.email)}</td>
235
+ <td>\${u.role ? badge(u.role, 'blue') : badge('—','gray')}</td>
236
+ <td>\${u.isEmailVerified ? badge('✓ verified','green') : badge('unverified','gray')}</td>
237
+ <td>\${u.isTotpEnabled ? badge('on','green') : badge('off','gray')}</td>
238
+ <td>\${ts(u.createdAt)}</td>
239
+ <td><button class="btn btn-danger" onclick="deleteUser('\${esc(u.id)}',''\${esc(u.email)}'')">Delete</button></td>
240
+ </tr>\`).join('')}
241
+ </tbody>
242
+ </table>
243
+ </div>
244
+ \${pagerHtml(_state.users.page, hasMore, "_state.users.page--;renderUsers()", "_state.users.page++;renderUsers()")}
245
+ </div>\`;
246
+ } catch (e) {
247
+ main.innerHTML = '<div class="alert alert-error">' + esc(e.message) + '</div>';
248
+ }
249
+ }
250
+ async function deleteUser(id, email) {
251
+ if (!confirm('Delete user ' + email + '? This cannot be undone.')) return;
252
+ try {
253
+ await api('DELETE', '/admin/api/users/' + encodeURIComponent(id));
254
+ flash('User deleted');
255
+ renderUsers();
256
+ } catch (e) { flash(e.message, 'error'); }
257
+ }
258
+
259
+ // ---- Sessions ------------------------------------------------------------
260
+ async function renderSessions() {
261
+ const main = document.getElementById('main');
262
+ main.innerHTML = '<div class="card"><div class="card-header"><h2>Sessions</h2><span class="meta"><span class="spinner"></span></span></div></div>';
263
+ try {
264
+ const { sessions, total } = await api('GET', '/admin/api/sessions?limit=' + PAGE_SIZE + '&offset=' + (_state.sessions.page * PAGE_SIZE));
265
+ const hasMore = (_state.sessions.page + 1) * PAGE_SIZE < total;
266
+ main.innerHTML = \`
267
+ <div class="card">
268
+ <div class="card-header"><h2>Active Sessions</h2><span class="meta">\${total} total</span></div>
269
+ <div class="table-wrap">
270
+ <table>
271
+ <thead><tr><th>Handle</th><th>User ID</th><th>IP</th><th>User Agent</th><th>Created</th><th>Last Active</th><th>Expires</th><th></th></tr></thead>
272
+ <tbody>\${sessions.length === 0 ? '<tr><td colspan="8"><div class="empty">No sessions</div></td></tr>' :
273
+ sessions.map(s => \`<tr>
274
+ <td style="font-family:monospace;font-size:.75rem">\${esc(s.sessionHandle.slice(0,12))}…</td>
275
+ <td style="font-family:monospace;font-size:.75rem">\${esc(s.userId)}</td>
276
+ <td>\${esc(s.ipAddress || '—')}</td>
277
+ <td title="\${esc(s.userAgent || '')}" style="max-width:160px">\${esc((s.userAgent || '—').slice(0,40))}</td>
278
+ <td>\${ts(s.createdAt)}</td>
279
+ <td>\${ts(s.lastActiveAt)}</td>
280
+ <td>\${ts(s.expiresAt)}</td>
281
+ <td><button class="btn btn-danger" onclick="revokeSession('\${esc(s.sessionHandle)}')">Revoke</button></td>
282
+ </tr>\`).join('')}
283
+ </tbody>
284
+ </table>
285
+ </div>
286
+ \${pagerHtml(_state.sessions.page, hasMore, "_state.sessions.page--;renderSessions()", "_state.sessions.page++;renderSessions()")}
287
+ </div>\`;
288
+ } catch (e) {
289
+ main.innerHTML = '<div class="alert alert-error">' + esc(e.message) + '</div>';
290
+ }
291
+ }
292
+ async function revokeSession(handle) {
293
+ try {
294
+ await api('DELETE', '/admin/api/sessions/' + encodeURIComponent(handle));
295
+ flash('Session revoked');
296
+ renderSessions();
297
+ } catch (e) { flash(e.message, 'error'); }
298
+ }
299
+
300
+ // ---- Roles ---------------------------------------------------------------
301
+ async function renderRoles() {
302
+ const main = document.getElementById('main');
303
+ main.innerHTML = '<div class="card"><div class="card-header"><h2>Roles</h2><span class="meta"><span class="spinner"></span></span></div></div>';
304
+ try {
305
+ const { roles } = await api('GET', '/admin/api/roles');
306
+ let html = '<div class="card"><div class="card-header"><h2>Roles & Permissions</h2></div>';
307
+ if (roles.length === 0) {
308
+ html += '<div class="empty">No roles defined</div>';
309
+ } else {
310
+ html += '<div class="table-wrap"><table><thead><tr><th>Role</th><th>Permissions</th><th></th></tr></thead><tbody>';
311
+ for (const r of roles) {
312
+ html += \`<tr>
313
+ <td><strong>\${esc(r.name)}</strong></td>
314
+ <td>\${r.permissions.length === 0 ? '<span style="color:#9ca3af">none</span>' : r.permissions.map(p => badge(p,'blue')).join(' ')}</td>
315
+ <td><button class="btn btn-danger" onclick="deleteRole('\${esc(r.name)}')">Delete</button></td>
316
+ </tr>\`;
317
+ }
318
+ html += '</tbody></table></div>';
319
+ }
320
+ // Create role form
321
+ html += \`<div style="padding:1rem 1.5rem;border-top:1px solid #f3f4f6">
322
+ <div class="form-row">
323
+ <input type="text" id="new-role-name" placeholder="Role name" style="width:180px">
324
+ <input type="text" id="new-role-perms" placeholder="Permissions (comma-separated)">
325
+ <button class="btn btn-primary btn-sm" onclick="createRole()">Add Role</button>
326
+ </div>
327
+ </div></div>\`;
328
+ main.innerHTML = html;
329
+ } catch (e) {
330
+ main.innerHTML = '<div class="alert alert-error">' + esc(e.message) + '</div>';
331
+ }
332
+ }
333
+ async function createRole() {
334
+ const name = document.getElementById('new-role-name').value.trim();
335
+ const perms = document.getElementById('new-role-perms').value.split(',').map(s => s.trim()).filter(Boolean);
336
+ if (!name) return;
337
+ try {
338
+ await api('POST', '/admin/api/roles', { name, permissions: perms });
339
+ flash('Role created');
340
+ renderRoles();
341
+ } catch (e) { flash(e.message, 'error'); }
342
+ }
343
+ async function deleteRole(name) {
344
+ if (!confirm('Delete role "' + name + '"?')) return;
345
+ try {
346
+ await api('DELETE', '/admin/api/roles/' + encodeURIComponent(name));
347
+ flash('Role deleted');
348
+ renderRoles();
349
+ } catch (e) { flash(e.message, 'error'); }
350
+ }
351
+
352
+ // ---- Tenants -------------------------------------------------------------
353
+ async function renderTenants() {
354
+ const main = document.getElementById('main');
355
+ main.innerHTML = '<div class="card"><div class="card-header"><h2>Tenants</h2><span class="meta"><span class="spinner"></span></span></div></div>';
356
+ try {
357
+ const { tenants } = await api('GET', '/admin/api/tenants');
358
+ let html = '<div class="card"><div class="card-header"><h2>Tenants</h2><span class="meta">' + tenants.length + ' total</span></div>';
359
+ html += '<div class="table-wrap"><table><thead><tr><th>ID</th><th>Name</th><th>Status</th><th>Created</th><th></th></tr></thead><tbody>';
360
+ if (tenants.length === 0) {
361
+ html += '<tr><td colspan="5"><div class="empty">No tenants</div></td></tr>';
362
+ } else {
363
+ for (const t of tenants) {
364
+ html += \`<tr>
365
+ <td style="font-family:monospace;font-size:.75rem">\${esc(t.id)}</td>
366
+ <td><strong>\${esc(t.name)}</strong></td>
367
+ <td>\${t.isActive !== false ? badge('active','green') : badge('inactive','red')}</td>
368
+ <td>\${ts(t.createdAt)}</td>
369
+ <td><button class="btn btn-danger" onclick="deleteTenant('\${esc(t.id)}')">Delete</button></td>
370
+ </tr>\`;
371
+ }
372
+ }
373
+ html += '</tbody></table></div>';
374
+ // Create tenant form
375
+ html += \`<div style="padding:1rem 1.5rem;border-top:1px solid #f3f4f6">
376
+ <div class="form-row">
377
+ <input type="text" id="new-tenant-name" placeholder="Tenant name" style="width:240px">
378
+ <button class="btn btn-primary btn-sm" onclick="createTenant()">Add Tenant</button>
379
+ </div>
380
+ </div></div>\`;
381
+ main.innerHTML = html;
382
+ } catch (e) {
383
+ main.innerHTML = '<div class="alert alert-error">' + esc(e.message) + '</div>';
384
+ }
385
+ }
386
+ async function createTenant() {
387
+ const name = document.getElementById('new-tenant-name').value.trim();
388
+ if (!name) return;
389
+ try {
390
+ await api('POST', '/admin/api/tenants', { name, isActive: true });
391
+ flash('Tenant created');
392
+ renderTenants();
393
+ } catch (e) { flash(e.message, 'error'); }
394
+ }
395
+ async function deleteTenant(id) {
396
+ if (!confirm('Delete tenant ' + id + '?')) return;
397
+ try {
398
+ await api('DELETE', '/admin/api/tenants/' + encodeURIComponent(id));
399
+ flash('Tenant deleted');
400
+ renderTenants();
401
+ } catch (e) { flash(e.message, 'error'); }
402
+ }
403
+ </script>
404
+ </body>
405
+ </html>`;
406
+ }
407
+ // ---------------------------------------------------------------------------
408
+ // Admin REST API + UI router
409
+ // ---------------------------------------------------------------------------
410
+ function createAdminRouter(userStore, options) {
411
+ const router = (0, express_1.Router)();
412
+ const guard = adminAuth(options.adminSecret);
413
+ const featSessions = !!options.sessionStore;
414
+ const featRoles = !!options.rbacStore;
415
+ const featTenants = !!options.tenantStore;
416
+ // GET /admin — serve the HTML UI
417
+ router.get('/', (_req, res) => {
418
+ res.setHeader('Content-Type', 'text/html; charset=utf-8');
419
+ res.send(buildAdminHtml('/admin', { sessions: featSessions, roles: featRoles, tenants: featTenants }));
420
+ });
421
+ // GET /admin/api/ping — health / auth check
422
+ router.get('/api/ping', guard, (_req, res) => {
423
+ res.json({ ok: true, features: { sessions: featSessions, roles: featRoles, tenants: featTenants } });
424
+ });
425
+ // ---- Users ----------------------------------------------------------------
426
+ // GET /admin/api/users?limit=&offset=
427
+ router.get('/api/users', guard, async (req, res) => {
428
+ try {
429
+ const limit = Math.min(parseInt(req.query['limit'] || '20', 10), 100);
430
+ const offset = parseInt(req.query['offset'] || '0', 10);
431
+ if (!userStore.listUsers) {
432
+ res.status(501).json({ error: 'IUserStore.listUsers is not implemented', users: [], total: 0 });
433
+ return;
434
+ }
435
+ const users = await userStore.listUsers(limit, offset);
436
+ // Strip sensitive fields before sending to admin
437
+ const safe = users.map(u => ({
438
+ id: u.id,
439
+ email: u.email,
440
+ role: u.role,
441
+ isEmailVerified: u.isEmailVerified,
442
+ isTotpEnabled: u.isTotpEnabled,
443
+ phoneNumber: u.phoneNumber,
444
+ createdAt: u['createdAt'],
445
+ }));
446
+ // Return total as the count of users returned (best-effort — stores may not expose total)
447
+ res.json({ users: safe, total: safe.length + offset + (safe.length === limit ? 1 : 0) });
448
+ }
449
+ catch (err) {
450
+ res.status(500).json({ error: 'Internal server error' });
451
+ }
452
+ });
453
+ // GET /admin/api/users/:id
454
+ router.get('/api/users/:id', guard, async (req, res) => {
455
+ try {
456
+ const user = await userStore.findById(req.params['id']);
457
+ if (!user) {
458
+ res.status(404).json({ error: 'User not found' });
459
+ return;
460
+ }
461
+ res.json({
462
+ id: user.id, email: user.email, role: user.role,
463
+ isEmailVerified: user.isEmailVerified, isTotpEnabled: user.isTotpEnabled,
464
+ });
465
+ }
466
+ catch {
467
+ res.status(500).json({ error: 'Internal server error' });
468
+ }
469
+ });
470
+ // DELETE /admin/api/users/:id — delete user (requires userStore to have a delete method if available)
471
+ router.delete('/api/users/:id', guard, async (req, res) => {
472
+ try {
473
+ const store = userStore;
474
+ if (typeof store['deleteUser'] === 'function') {
475
+ await store['deleteUser'](req.params['id']);
476
+ res.json({ success: true });
477
+ }
478
+ else {
479
+ res.status(501).json({ error: 'IUserStore.deleteUser is not implemented' });
480
+ }
481
+ }
482
+ catch {
483
+ res.status(500).json({ error: 'Internal server error' });
484
+ }
485
+ });
486
+ // ---- Sessions -------------------------------------------------------------
487
+ // GET /admin/api/sessions?limit=&offset=
488
+ router.get('/api/sessions', guard, async (req, res) => {
489
+ if (!options.sessionStore) {
490
+ res.status(404).json({ error: 'Session store not configured' });
491
+ return;
492
+ }
493
+ try {
494
+ const limit = Math.min(parseInt(req.query['limit'] || '20', 10), 100);
495
+ const offset = parseInt(req.query['offset'] || '0', 10);
496
+ if (!options.sessionStore.getAllSessions) {
497
+ res.status(501).json({ error: 'ISessionStore.getAllSessions is not implemented', sessions: [], total: 0 });
498
+ return;
499
+ }
500
+ const sessions = await options.sessionStore.getAllSessions(limit, offset);
501
+ res.json({ sessions, total: sessions.length + offset + (sessions.length === limit ? 1 : 0) });
502
+ }
503
+ catch {
504
+ res.status(500).json({ error: 'Internal server error' });
505
+ }
506
+ });
507
+ // DELETE /admin/api/sessions/:handle
508
+ router.delete('/api/sessions/:handle', guard, async (req, res) => {
509
+ if (!options.sessionStore) {
510
+ res.status(404).json({ error: 'Session store not configured' });
511
+ return;
512
+ }
513
+ try {
514
+ await options.sessionStore.revokeSession(decodeURIComponent(req.params['handle']));
515
+ res.json({ success: true });
516
+ }
517
+ catch {
518
+ res.status(500).json({ error: 'Internal server error' });
519
+ }
520
+ });
521
+ // ---- Roles & Permissions --------------------------------------------------
522
+ // GET /admin/api/roles
523
+ router.get('/api/roles', guard, async (_req, res) => {
524
+ if (!options.rbacStore) {
525
+ res.status(404).json({ error: 'RBAC store not configured' });
526
+ return;
527
+ }
528
+ try {
529
+ if (!options.rbacStore.getAllRoles) {
530
+ res.status(501).json({ error: 'IRolesPermissionsStore.getAllRoles is not implemented', roles: [] });
531
+ return;
532
+ }
533
+ const roleNames = await options.rbacStore.getAllRoles();
534
+ const roles = await Promise.all(roleNames.map(async (name) => ({
535
+ name,
536
+ permissions: await options.rbacStore.getPermissionsForRole(name),
537
+ })));
538
+ res.json({ roles });
539
+ }
540
+ catch {
541
+ res.status(500).json({ error: 'Internal server error' });
542
+ }
543
+ });
544
+ // POST /admin/api/roles
545
+ router.post('/api/roles', guard, async (req, res) => {
546
+ if (!options.rbacStore) {
547
+ res.status(404).json({ error: 'RBAC store not configured' });
548
+ return;
549
+ }
550
+ try {
551
+ const { name, permissions } = req.body;
552
+ if (!name) {
553
+ res.status(400).json({ error: 'name is required' });
554
+ return;
555
+ }
556
+ await options.rbacStore.createRole(name, permissions);
557
+ res.json({ success: true });
558
+ }
559
+ catch {
560
+ res.status(500).json({ error: 'Internal server error' });
561
+ }
562
+ });
563
+ // DELETE /admin/api/roles/:name
564
+ router.delete('/api/roles/:name', guard, async (req, res) => {
565
+ if (!options.rbacStore) {
566
+ res.status(404).json({ error: 'RBAC store not configured' });
567
+ return;
568
+ }
569
+ try {
570
+ await options.rbacStore.deleteRole(decodeURIComponent(req.params['name']));
571
+ res.json({ success: true });
572
+ }
573
+ catch {
574
+ res.status(500).json({ error: 'Internal server error' });
575
+ }
576
+ });
577
+ // ---- Tenants --------------------------------------------------------------
578
+ // GET /admin/api/tenants
579
+ router.get('/api/tenants', guard, async (_req, res) => {
580
+ if (!options.tenantStore) {
581
+ res.status(404).json({ error: 'Tenant store not configured' });
582
+ return;
583
+ }
584
+ try {
585
+ const tenants = await options.tenantStore.getAllTenants();
586
+ res.json({ tenants });
587
+ }
588
+ catch {
589
+ res.status(500).json({ error: 'Internal server error' });
590
+ }
591
+ });
592
+ // POST /admin/api/tenants
593
+ router.post('/api/tenants', guard, async (req, res) => {
594
+ if (!options.tenantStore) {
595
+ res.status(404).json({ error: 'Tenant store not configured' });
596
+ return;
597
+ }
598
+ try {
599
+ const { name, isActive } = req.body;
600
+ if (!name) {
601
+ res.status(400).json({ error: 'name is required' });
602
+ return;
603
+ }
604
+ const tenant = await options.tenantStore.createTenant({ name, isActive: isActive ?? true });
605
+ res.json({ tenant });
606
+ }
607
+ catch {
608
+ res.status(500).json({ error: 'Internal server error' });
609
+ }
610
+ });
611
+ // DELETE /admin/api/tenants/:id
612
+ router.delete('/api/tenants/:id', guard, async (req, res) => {
613
+ if (!options.tenantStore) {
614
+ res.status(404).json({ error: 'Tenant store not configured' });
615
+ return;
616
+ }
617
+ try {
618
+ await options.tenantStore.deleteTenant(decodeURIComponent(req.params['id']));
619
+ res.json({ success: true });
620
+ }
621
+ catch {
622
+ res.status(500).json({ error: 'Internal server error' });
623
+ }
624
+ });
625
+ return router;
626
+ }
627
+ //# sourceMappingURL=admin.router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.router.js","sourceRoot":"","sources":["../../src/router/admin.router.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"auth.router.d.ts","sourceRoot":"","sources":["../../src/router/auth.router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,cAAc,EAAE,MAAM,SAAS,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAQzD,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAIrE,MAAM,WAAW,aAAa;IAC5B,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,mHAAmH;IACnH,WAAW,CAAC,EAAE,cAAc,CAAC;CAC9B;AAgBD,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,UAAU,EACrB,MAAM,EAAE,UAAU,EAClB,OAAO,GAAE,aAAkB,GAC1B,MAAM,CAsUR"}
1
+ {"version":3,"file":"auth.router.d.ts","sourceRoot":"","sources":["../../src/router/auth.router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,cAAc,EAAE,MAAM,SAAS,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,oCAAoC,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAUzD,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAIrE,MAAM,WAAW,aAAa;IAC5B,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,mHAAmH;IACnH,WAAW,CAAC,EAAE,cAAc,CAAC;CAC9B;AA4BD,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,UAAU,EACrB,MAAM,EAAE,UAAU,EAClB,OAAO,GAAE,aAAkB,GAC1B,MAAM,CAueR"}